smoj2017(树链剖分+线段树/LCT)

来源:互联网 发布:绿岸网络2017 编辑:程序博客网 时间:2024/06/03 13:19

还是在比赛时虐我的题,我当时做到一半回家了。回到家之后只会打暴力,结果看到米娜都ac了,顿时鸡都不想吃了。没想到是n方过十万…

题意:有一棵n个点的萌萌的黑白树,一开始结点都是黑的。搞了m件事情,每件事情要么可以变一个点的颜色,或者询问一个点和它同色的连通块的大小。

这个问题完全可以放在一个图上。之所以在一棵树上,因为树有顺序,每个点不必维护整个连通块的信息,只需要维护子树信息就可以了。

0表示黑,1表示白
每个点维护两个信息,ans0和ans1。分别表示当这个点是黑色/白色时,该点和它的子树构成的黑色/白色的连通块大小。(也许经历了所有的悲伤,这个就能想出来吧)

然后先考虑有这两个信息,怎么得到询问的答案。经过小小的分析,是这样的

假设询问点x,就不断的往父亲上跳,找到距离它最远的,与它路径上的点都是同色的祖先p。p的答案就是询问的答案。

考虑修改点x,x原来的颜色是col,同样找到那个祖先p,由fa[x]到p的路径上的ans[col]-=(x的ans[col])。再改变x的颜色,再找p,由fa[x]到p的路径上的ans[col^1]+=(x的ans[col^1])。
这个链修改,单点询问,可用树链剖分+线段树实现。至于第一个不同色的点,在线段树上维护这个信息就可以了。

觉得树剖很愚蠢,追求复杂度的同学也可以用LCT模拟上述过程。(然而并没有Link和Cut)

其实这题就是一棵裸的LCT。每个点都多开两个点,分别像黑色的儿子和白色的儿子连边。改颜色就模拟来Link和Cut。答案就是连通块大小。LCT不会维护连通块大小的?点这里

花俏的LCT

#include <iostream>#include <fstream>#include <algorithm>#include <cmath>#include <ctime>#include <cstdio>#include <cstdlib>#include <cstring>using namespace std;#define mmst(a, b) memset(a, b, sizeof(a))#define mmcp(a, b) memcpy(a, b, sizeof(b))#define imax(a, b) (((a)>(b)) ? (a) : (b))typedef long long LL;const int N=200200;void read(int &hy){    hy=0;    char cc=getchar();    while(cc>'9'||cc<'0')    cc=getchar();    while(cc>='0'&&cc<='9')    {        hy=(hy<<3)+(hy<<1)+cc-'0';        cc=getchar();    }}int n,q;int to[N],nex[N],head[N],cnt;int fa[N],siz[N];void add(int u,int v){    to[++cnt]=v;    nex[cnt]=head[u];    head[u]=cnt;}void dfs(int x){    siz[x]=1;    for(int h=head[x];h;h=nex[h])    if(to[h]!=fa[x])    {        fa[to[h]]=x;        dfs(to[h]);        siz[x]+=siz[to[h]];    }}struct tree{    tree *c[2],*f,*pp;    bool col,k[2];    int ad[2],ans[2];    int d(){return f->c[1]==this;}    void sc(tree *x,int d){(c[d]=x)->f=this;}}nil[N],*ro[N];void up(tree *x){    x->k[0]=x->k[1]=x->col;    if(x->c[0]!=nil)    {        x->k[0]=x->k[0] | x->c[0]->k[0];        x->k[1]=x->k[1] & x->c[0]->k[1];    }    if(x->c[1]!=nil)    {        x->k[0]=x->k[0] | x->c[1]->k[0];        x->k[1]=x->k[1] & x->c[1]->k[1];    }}void down(tree *x){    for(int i=0;i<2;i++)    {        x->c[0]->ad[i]+=x->ad[i];        x->c[0]->ans[i]+=x->ad[i];        x->c[1]->ad[i]+=x->ad[i];        x->c[1]->ans[i]+=x->ad[i];        x->ad[i]=0;    }}void work(tree *x){    if(x->f!=nil)    work(x->f);    down(x);}void zig(tree *x){    tree *y=x->f;    int d=x->d();    y->sc(x->c[!d],d);    if(y->f==nil)    x->f=nil;    else    y->f->sc(x,y->d());    x->sc(y,!d);    x->pp=y->pp;    y->pp=nil;    up(y);    up(x);}void splay(tree *x){    work(x);    for(tree *y;x->f!=nil;)    {        y=x->f;        if(y->f!=nil)        (x->d() ^ y->d()) ? zig(x) : zig(y);        zig(x);    }} void Access(tree *x){    tree *y=nil;    while(x!=nil)    {        splay(x);        if(x->c[1]!=nil)        {            x->c[1]->f=nil;            x->c[1]->pp=x;        }        x->c[1]=y;        if(y!=nil)        y->f=x;        y->pp=nil;        up(x);        y=x;        x=x->pp;    }}tree *find(tree *x){    Access(x);    splay(x);    int co=x->col;    tree *y;    while(x!=nil)    {        if((x->c[1]->k[co]==co||x->c[1]==nil)&&x->col==co)        {            y=x;            x=x->c[0];        }        else        x=x->c[1];    }    splay(y);    return y;}int main(){    nil->c[0]=nil->c[1]=nil->f=nil->pp=nil;    cin>>n;    for(int i=1;i<=n;i++)    {        nil[i]=nil[0];        ro[i]=&nil[i];    }    for(int i=1;i<n;i++)    {        int u,v;        read(u);        read(v);        add(u,v);        add(v,u);    }    dfs(1);    for(int i=1;i<=n;i++)    ro[i]->ans[0]=siz[i],ro[i]->ans[1]=1;    for(int i=2;i<=n;i++)    ro[i]->pp=ro[fa[i]];    cin>>q;    while(q--)    {        int ops,x;        read(ops);        read(x);        tree *hy=find(ro[x]);        int co=ro[x]->col;        if(!ops)        printf("%d\n",hy->ans[co]);        else        {            int si=ro[x]->ans[co];            int tu=si;            ro[x]->ans[co]+=si;            hy->ans[co]-=si;            hy->c[1]->ans[co]-=si;            hy->c[1]->ad[co]-=si;            if(fa[hy-nil])            ro[fa[hy-nil]]->ans[co]-=si;            co^=1;            si=ro[x]->ans[co];            splay(ro[x]);            ro[x]->col^=1;            up(ro[x]);            ro[x]->ans[co]=0;            hy=find(ro[x]);            hy->ans[co]+=si;            hy->c[1]->ans[co]+=si;            hy->c[1]->ad[co]+=si;            if(fa[hy-nil])            ro[fa[hy-nil]]->ans[co]+=si;        }    }    return 0;}
原创粉丝点击