BZOJ 3786 星系探索 splay维护dfs序

来源:互联网 发布:淘宝店铺未来发展趋势 编辑:程序博客网 时间:2024/05/16 23:19

一开始看到子树操作想要树剖,但是仔细想想之后发现树剖没有办法维护一个点到根节点的距离,而且无法维护对应关系,后来就想到了使用dfs序,这样只要维护前缀和就可以快速求出一个点到根节点的距离,由于有换边操作,所以我们要使用splay维护,这道题要注意一个细节,就是每次想要提取出来一个区间需要先找到这个区间的前驱后继,都做完以后这题就能过啦

#include<cstdio>#include<cstdlib>#include<ctime>#include<cmath>#include<cstring>#include<string>#include<iostream>#include<iomanip>#include<algorithm>using namespace std;typedef long long ll;struct splay{    splay *fa,*ls,*rs;    ll v,sum,zsize,fsize,add_mark;    bool pr;    splay();    void push_up();    void add_v(ll val);    void push_down();}*null=new splay(),mempool[300000],*root;int dfsx[300000];int in_t[300000];int out_t[300000];int fir[300000];int nex[300000];struct bian{    int r;}a[600000];int topppp;ll v[300000];int top=0;void dfs(int u,int fro){    dfsx[++top]=u;    in_t[u]=top;    for(int o=fir[u];o!=0;o=nex[o])        if(a[o].r!=fro)            dfs(a[o].r,u);    dfsx[++top]=u;    out_t[u]=top;}void splay :: push_up(){    sum=ls->sum+v+rs->sum;    zsize=ls->zsize+pr+rs->zsize;    fsize=ls->fsize+(1-pr)+rs->fsize;}void splay :: push_down(){    if(add_mark)    {        if(ls!=null) ls->add_v(add_mark);        if(rs!=null) rs->add_v(add_mark);        add_mark=0;    }}void splay :: add_v(ll val){    if(pr) v+=val;    else v-=val;    sum+=(zsize-fsize)*val;    add_mark+=val;}splay :: splay(){    fa=ls=rs=null;    v=sum=zsize=fsize=add_mark=pr=0;}void right(splay *x){    splay *y=x->fa;    y->ls=x->rs;    x->rs->fa=y;    x->rs=y;    x->fa=y->fa;    if(y==y->fa->ls) y->fa->ls=x;    if(y==y->fa->rs) y->fa->rs=x;    y->fa=x;    y->push_up();    if(y==root) root=x;}void left(splay *x){    splay *y=x->fa;    y->rs=x->ls;    x->ls->fa=y;    x->ls=y;    x->fa=y->fa;    if(y==y->fa->ls) y->fa->ls=x;    if(y==y->fa->rs) y->fa->rs=x;    y->fa=x;    y->push_up();    if(y==root) root=x;}void push_down(splay *x){    if(x->fa!=null) push_down(x->fa);    x->push_down();}void splaying(splay *x,splay *goal){    push_down(x);    while(1)    {        splay *y=x->fa;        splay *z=y->fa;        //cout<<x<<" "<<y->rs<<endl;//<<null<<" "<<endl;        if(y==goal) break;        if(z==goal)        {            if(x==y->ls) right(x);            else left(x);            break;        }        if(x==y->ls)        {            if(y==z->ls) right(y);            right(x);        }        else if(x==y->rs)        {            if(y==z->rs) left(y);            left(x);        }    }    x->push_up();}splay *maketree(int l,int r){    if(l>r) return null;    int mid=l+r>>1;    splay *x=&mempool[mid];    if(mid==in_t[dfsx[mid]])    {        x->v=v[dfsx[mid]];        x->sum=v[dfsx[mid]];        x->pr=true;        x->zsize=1;    }    else    {        x->v=-v[dfsx[mid]];        x->sum=-v[dfsx[mid]];        x->pr=false;        x->fsize=1;    }    x->ls=maketree(l,mid-1);    x->ls->fa=x;    x->rs=maketree(mid+1,r);    x->rs->fa=x;    x->push_up();    return x;}splay* find_hou(splay *o){    if(o->ls!=null) return find_hou(o->ls);    return o;}splay* find_qian(splay *o){    if(o->rs!=null) return find_qian(o->rs);    return o;}ll find_ans(int x){    splaying(&mempool[in_t[1]],null);    splay *mid=find_qian(root->ls);    splaying(&mempool[in_t[x]],null);    splay *midd=find_hou(root->rs);    splaying(mid,null);    splaying(midd,root);    return root->rs->ls->sum;}void change(int x,int v){    splaying(&mempool[in_t[x]],null);    splay *mid=find_qian(root->ls);    splaying(&mempool[out_t[x]],null);    splay *midd=find_hou(root->rs);    splaying(mid,null);    splaying(midd,root);    root->rs->ls->add_v(v);    root->rs->push_up();    root->push_up();}void move_to_wz(int x,int y){    splaying(&mempool[in_t[x]],null);    splay *mid=find_qian(root->ls);    splaying(&mempool[out_t[x]],null);    splay *midd=find_hou(root->rs);    splaying(mid,null);    splaying(midd,root);    splay *qie=root->rs->ls;    qie->fa=null;    root->rs->ls=null;    root->rs->push_up();    root->push_up();    splaying(&mempool[in_t[y]],null);    splay *middd=find_hou(root->rs);    splaying(middd,root);    root->rs->ls=qie;    qie->fa=root->rs;    root->rs->push_up();    root->push_up();}void add_edge(int l,int r){    //cout<<l<<" "<<r<<endl;    a[++topppp].r=r;    nex[topppp]=fir[l];    fir[l]=topppp;}char s[10];int main(){    ll n,m;    scanf("%lld",&n);    for(int i=1;i<n;i++)    {        int x;        scanf("%d",&x);        add_edge(x,i+1);    }    for(int i=1;i<=n;i++) scanf("%lld",&v[i]);    dfs(1,0);    root=maketree(0,top+1);    scanf("%lld",&m);    for(int i=1;i<=m;i++)    {        scanf("%s",s);        if(s[0]=='Q')        {            int x;            scanf("%d",&x);            printf("%lld\n",find_ans(x));        }        else if(s[0]=='F')        {            ll x,val;            scanf("%lld%lld",&x,&val);            change(x,val);        }        else        {            int x,y;            scanf("%d%d",&x,&y);            move_to_wz(x,y);        }    }}
1 1
原创粉丝点击