bzoj千题计划274:bzoj3779: 重组病毒

http://www.lydsy.com/JudgeOnline/problem.php?id=3779

 

有一棵树,初始每个节点有不同的颜色

操作1:根节点到x的路径上的点 染上一种没有出现过的颜色

操作2:操作1后把x换成根

操作3:定义点x的点权为x到根节点路径上不同颜色的数量,查询x的子树点权和

 

LCT+线段树+dfs序

dfs一遍得到每个点的dfs序,

以及每个点子树的dfs序范围,记点x的子树dfs序范围为 [Lx,Rx]

线段树以dfs序为顺序维护

 

操作1就是access,

一条Preferred Path 上所有点的颜色相同

在轻重链交换的时候才会涉及到点权的修改

如果lct上父节点x和子节点y之间的边由重链变轻链,那么lct上 以子节点y为根的子树的所有点 的点权减1

实现就是找到t的Auxiliary Tree 上深度最小的点z, 区间[Lz,Rz] 减1

如果lct上父节点x和子节点y之间的边由轻链变重链,那么lct上 以子节点y为根的子树的所有点 的点权加1

实现就是找到t的Auxiliary Tree 上深度最小的点z, 区间[Lz,Rz] 加1

 

操作2就是LCT的换根操作

不用刻意的去维护换根对线段树的影响,因为换根之前会执行操作1,access

点到新的根节点路径上的颜色数量 就等于 点到原来根节点路径上的颜色数量

 

查询操作:

分析点x和根节点root 子树的包含关系

若x==root,那就是查询整棵树

若x在root的子树内,直接查x的子树

若root在x的子树内,设root在x的子节点p的子树内,那就是查询整棵树除去p的子树的部分

查询子树就是 线段树按dfs序维护的一段连续的区间

 

#include<cmath>
#include<cstdio>
#include<iostream>

#define N 100001

using namespace std;

typedef long long LL;

int n;
int front[N],to[N<<1],nxt[N<<1],tot;

int id[N],dy[N],lst[N],tim;
int dep[N];
int lim,F[N][18];

int fa[N],ch[N][2],root;
bool rev[N];

LL sum[N<<2];
int siz[N<<2],tag[N<<2];

int st[N],top;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

void add(int u,int v)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
}

void dfs(int x)
{
    id[x]=++tim;
    dy[tim]=x;
    for(int i=front[x];i;i=nxt[i])
        if(to[i]!=fa[x])
        {
            dep[to[i]]=dep[x]+1;
            F[to[i]][0]=x;
            fa[to[i]]=x;
            dfs(to[i]);
        }
    lst[x]=tim;
}

void build(int k,int l,int r)
{
    siz[k]=r-l+1;
    if(l==r)
    {
        sum[k]=dep[dy[l]];
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    sum[k]=sum[k<<1]+sum[k<<1|1];
}

void tagging(int k,int w)
{
    sum[k]+=w*siz[k];
    tag[k]+=w;
}

void push_down(int k)
{
    tagging(k<<1,tag[k]);
    tagging(k<<1|1,tag[k]);
    tag[k]=0;
}

void change(int k,int l,int r,int opl,int opr,int w)
{
    if(l>=opl && r<=opr)
    {
        tagging(k,w);
        return;
    }
    if(tag[k]) push_down(k);
    int mid=l+r>>1;
    if(opl<=mid) change(k<<1,l,mid,opl,opr,w);
    if(opr>mid) change(k<<1|1,mid+1,r,opl,opr,w);
    sum[k]=sum[k<<1]+sum[k<<1|1];
}

void Change(int x,int w)
{
    if(x==root) change(1,1,n,1,n,w);
    else if(id[root]>id[x] && id[root]<=lst[x])    
    {
        int t=root,c=dep[root]-dep[x]-1;
        for(int i=lim;i>=0;--i)
            if(c&(1<<i)) t=F[t][i];
        if(id[t]>1) change(1,1,n,1,id[t]-1,w);
        if(lst[t]<n) change(1,1,n,lst[t]+1,n,w);
    }
    else change(1,1,n,id[x],lst[x],w);
}

LL query(int k,int l,int r,int opl,int opr)
{
    if(l==opl && r==opr) return sum[k];
    if(tag[k]) push_down(k);
    int mid=l+r>>1; LL res=0;
    if(opl<=mid) res+=query(k<<1,l,mid,opl,min(mid,opr));
    if(opr>mid) res+=query(k<<1|1,mid+1,r,max(mid+1,opl),opr);
    return res;
}

double Query(int x)
{
    if(x==root) return 1.0*query(1,1,n,1,n)/n;
    else if(id[root]>id[x] && id[root]<=lst[x])
    {
        int t=root,c=dep[root]-dep[x]-1;
        for(int i=lim;i>=0;--i)
            if(c&(1<<i)) t=F[t][i];
        int siz=id[t]-1+n-lst[t];
        LL res=0;
        if(id[t]>1) res+=query(1,1,n,1,id[t]-1);
        if(lst[t]<n) res+=query(1,1,n,lst[t]+1,n);
        return 1.0*res/siz;
    }
    return 1.0*query(1,1,n,id[x],lst[x])/(lst[x]-id[x]+1);
}

void down(int x)
{
    rev[x]^=1;
    if(ch[x][0]) rev[ch[x][0]]^=1;
    if(ch[x][1]) rev[ch[x][1]]^=1;
    std::swap(ch[x][0],ch[x][1]);
}

bool isroot(int x)
{
    return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x;
}

bool getson(int x)
{
    return ch[fa[x]][1]==x;
}

void rotate(int x)
{
    int y=fa[x],z=fa[y];
    bool k=ch[y][1]==x;
    if(!isroot(y)) ch[z][ch[z][1]==y]=x;
    ch[y][k]=ch[x][k^1]; ch[x][k^1]=y;
    fa[y]=x; fa[x]=z; fa[ch[y][k]]=y;
}

void splay(int x)
{
    st[top=1]=x;
    for(int i=x;!isroot(i);i=fa[i]) st[++top]=fa[i];
    for(int i=top;i;--i) 
        if(rev[st[i]]) down(st[i]);
    int y;
    while(!isroot(x))
    {
        y=fa[x];
        if(!isroot(y)) rotate(getson(x)==getson(y) ? y : x);
        rotate(x);
    }
}

int find_root(int x)
{
    if(rev[x]) down(x);
    while(ch[x][0])
    {
        x=ch[x][0];
        if(rev[x]) down(x);
    }
    return x;
}

void access(int x)
{
    int t=0;
    while(x)
    {
        splay(x);
        if(ch[x][1]) Change(find_root(ch[x][1]),1);
        ch[x][1]=t;
        if(t) Change(find_root(t),-1);
        t=x; x=fa[x];
    }
}

void maker_root(int x)
{
    access(x);
    splay(x);
    rev[x]^=1;
    root=x;
}

int main()
{
    freopen("recompile.in", "r", stdin);
    freopen("recompile.out", "w", stdout);
    int m;
    read(n); read(m);
    int u,v;
    for(int i=1;i<n;++i)
    {
        read(u); read(v);
        add(u,v);
    }
    dep[1]=1;
    dfs(1);
    lim=log(n)/log(2);
    for(int j=1;j<=lim;++j)
        for(int i=1;i<=n;++i)
            F[i][j]=F[F[i][j-1]][j-1];
    build(1,1,n);
    root=1;
    char c[3]; int x;
    while(m--)
    {
        scanf("%s",c);
        read(x);
        if(c[2]=='L') access(x);
        else if(c[2]=='C')     maker_root(x);
        else printf("%.10lf\n",Query(x));
    }
}

 

posted @ 2018-03-12 19:12  TRTTG  阅读(236)  评论(0编辑  收藏  举报