BZOJ3786: 星系探索 splay维护dfs序

来源:互联网 发布:商业银行存贷比数据 编辑:程序博客网 时间:2024/06/05 19:54

题目大意:n个点的树,m个操作
1.询问到根权值和
2.改变父亲,保证不出环
3.子树加
n<=100000,m<=300000,要开long long
toptree轻松虐,可惜我不会
因为本题的询问都是一个点到根的,根又不会变,因此可以通过维护入栈出栈序的方法,每个点入栈时向splay中push _ back一个正权值点,出栈时向splay中push _ back一个负权值点,这样从头到查询点之间的其它点会正负抵消。
改变父亲就将这个点入栈——出栈之间的一段提出来,插到父亲的入栈点之后。
入栈点cnt记为1,出栈点记为-1,则add标记对sum的增加量就是cnt之和*add,入栈点v+=add,出栈点v-=add。
注意权值有0,因此不能靠权值的正负来判断是入栈点还是出栈点,要单独记录。

#include<cstdio>#define gm 100001using namespace std;typedef long long ll;typedef const ll& cref;struct node{    ll sum,v,add;    char inv;    int cnt;    node *s[2],*f;    node();    node(cref,char);    inline void* operator new(size_t)    {        static unsigned char p[gm*sizeof(node)*2];        static size_t t=-1;        return ((node*)p)+ ++t;    }    inline bool r()    {        return this==f->s[1];    }    inline void up()    {        sum=v+s[0]->sum+s[1]->sum;        cnt=inv+s[0]->cnt+s[1]->cnt;    }    inline void plus(cref);    inline void down();}*nil=new node;node::node():sum(0),v(0),add(0),cnt(0),f(nil){s[0]=s[1]=nil;}node::node(cref v,char inv):sum(v),v(v),add(0),inv(inv),cnt(inv),f(nil){s[0]=s[1]=nil;}inline void node::plus(cref a){    if(this==nil) return;    add+=a;    if(~inv) v+=a;else v-=a;    sum+=cnt*a;}inline void node::down(){    if(f!=nil) f->down();    if(add)    s[0]->plus(add),s[1]->plus(add),add=0;}struct SplayTree{    typedef node* Iterator;    node *rt;    SplayTree(node *rt=nil):rt(rt){}    inline void rot(node *x)    {        static node *o,*y;        static bool k;        k=!x->r();        o=x->f,y=x->s[k];        if(o->f!=nil) o->f->s[o->r()]=x;        x->s[k]=o,o->s[!k]=y;        x->f=o->f,o->f=x,y->f=o;        o->up();    }    inline void splay(node *x)    {        x->down();        while(x->f!=nil)        {            if(x->f->f==nil) rot(x);            else if(x->r()==x->f->r()) rot(x->f),rot(x);            else rot(x),rot(x);        }        rt=x;        x->up();    }    inline void push_back(node *x)    {        if(rt==nil) {rt=x;return;}        node *now=rt;        while(now->s[1]!=nil) now=now->s[1];        splay(now);        now->s[1]=x;        x->f=now;        now->up();    }    inline node* push_back(cref v,char t)    {        node *x=new node(v,t);        push_back(x);        return x;    }    inline void push_back(SplayTree& v)    {        push_back(v.rt);        v.rt=nil;    }    inline SplayTree split_before(node *x)    {        splay(x);        x=rt->s[0];        rt->s[0]=x->f=nil;        rt->up();        return SplayTree(x);    }    inline SplayTree split_after(node *x)    {        splay(x);        x=rt->s[1];        rt->s[1]=x->f=nil;        rt->up();        return SplayTree(x);    }    inline void add(cref v)    {        rt->plus(v);    }    inline ll sum()    {        return rt->sum;    }}tree;int n,m,fat[gm],w[gm];char c;SplayTree::Iterator begin[gm],end[gm];struct e{    int t;    e *n;    e(int t,e *n):t(t),n(n){}}*f[gm];void dfs(int x){    begin[x]=tree.push_back(ll(w[x]),1);    for(e *i=f[x];i;i=i->n)    if(i->t!=fat[x])    dfs(i->t);    end[x]=tree.push_back(ll(-w[x]),-1);}inline ll query(int x){    SplayTree arc=tree.split_after(begin[x]);    ll ans=tree.sum();    tree.push_back(arc);    return ans;}inline void reset(int x,int y){    SplayTree pre=tree.split_before(begin[x]),arc=tree.split_after(end[x]);    pre.push_back(arc);    arc=pre.split_after(begin[y]);    tree.push_back(arc);    pre.push_back(tree);    tree.push_back(pre);}inline void add(int x,ll v){    SplayTree pre=tree.split_before(begin[x]),arc=tree.split_after(end[x]);    tree.add(v);    tree.push_back(arc);    pre.push_back(tree);    tree.push_back(pre);}int main(){    scanf("%d",&n);    for(int i=2;i<=n;++i)    {        scanf("%d",fat+i);        f[fat[i]]=new e(i,f[fat[i]]);    }    for(int i=1;i<=n;++i)    scanf("%d",w+i);    dfs(1);    scanf("%d",&m);    while(m--)    {        do c=getchar();while(c!='Q'&&c!='C'&&c!='F');        if(c=='Q')        {            int d;            scanf("%d",&d);            printf("%lld\n",query(d));        }        else if(c=='C')        {            int x,y;            scanf("%d%d",&x,&y);            reset(x,y);        }        else        {            int p,q;            scanf("%d%d",&p,&q);            add(p,q);        }    }    return 0;}
0 0
原创粉丝点击