bzoj4448(LCT)

来源:互联网 发布:打车软件 编辑:程序博客网 时间:2024/06/05 06:51

题面
题意是给你一棵树,在每个时刻标记一个点,或者问一条路径有多少个点在C时间前被标记了及路径长度。

这题好在可以离线,按时间排序后就取消了时间限制,操作变成标记一个点,询问就是问一条路径有几个点被标记了及路径长度。不会LCA,歧视树剖的我就水了棵LCT。

单点标记就把该点Splay到根,然后标记。
路径询问就分别Evert和Access两个端点,把路径放到一棵Splay上,在根上就可以得到这条路径的信息了。

#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))typedef long long LL;const int N=200100;int n,cnt,m;int ans[N],len[N];struct yy{    int ops,num,tim,u,v;}f[N];bool cmp(yy x,yy y){    if(x.tim==y.tim)    return x.ops>y.ops;    return x.tim<y.tim;}struct tree{    tree *c[2],*f,*pp;    int a,sum,siz;    bool flip;    int d(){return f->c[1]==this;}    void sc(tree *x,int d){(c[d]=x)->f=this;}}nil[N],*ro[N];tree *newtree(){    nil[++cnt]=nil[0];    nil[cnt].siz=1;    return nil+cnt;}void up(tree *x){    x->sum=x->a+x->c[0]->sum+x->c[1]->sum;    x->siz=x->c[0]->siz+x->c[1]->siz+1;}void down(tree *x){    if(!x->flip)    return;    swap(x->c[0],x->c[1]);    if(x->c[0]!=nil)    x->c[0]->flip^=1;    if(x->c[1]!=nil)    x->c[1]->flip^=1;    x->flip=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);    up(y);    up(x);    x->pp=y->pp;    y->pp=nil;}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;        up(x);        y->pp=nil;        y=x;        x=x->pp;    }}void Evert(tree *x){    Access(x);    splay(x);    x->flip^=1;}int main(){    nil->c[0]=nil->c[1]=nil->f=nil->pp=nil;    cin>>n;    for(int i=1;i<=n;i++)    ro[i]=newtree();    for(int i=1;i<=n;i++)    {        int x;        scanf("%d",&x);        if(x)        ro[i]->pp=ro[x];    }    cin>>m;    for(int i=1;i<=m;i++)    {        f[i].num=i;        scanf("%d",&f[i].ops);        if(f[i].ops==2)        {            scanf("%d",&f[i].u);            f[i].tim=i;        }        else        {            scanf("%d%d%d",&f[i].u,&f[i].v,&f[i].tim);            f[i].tim=i-f[i].tim-1;        }    }    sort(f+1,f+m+1,cmp);    for(int i=1;i<=m;i++)    {        if(f[i].ops==2)        {            splay(ro[f[i].u]);            ro[f[i].u]->a=1;            up(ro[f[i].u]);        }        else        {            Evert(ro[f[i].u]);            Access(ro[f[i].v]);            splay(ro[f[i].v]);            ans[f[i].num]=ro[f[i].v]->sum;            len[f[i].num]=ro[f[i].v]->siz;        }    }    for(int i=1;i<=m;i++)    if(len[i])    printf("%d %d\n",len[i],ans[i]);    return 0;}
原创粉丝点击