NOI模拟:Death(虚树)

题意:

小 F 堕入了梦魇的世界,一只巨大的魔爪,或者说,一棵根节点为 1 的有根树,每个节点有
一个危险值 wi w i
小 F 不会自己从梦境中醒来,她要在梦境中切断自己与梦魇的联系,才能逃离这个世界。
每次,小 F 都是从 1 号节点进入这个世界。
她要去编号为 x1,x2...xk x 1 , x 2 . . . x k 的节点上切断联系。
她希望知道她要经过的所有节点的危险度之和最小是多少(多次经过只算一次)。
支持:
1. 1xw 1 x w 在编号为 x x 的点下加一个危险值为 w w 的叶节点。
2. 2xw 2 x w fax f a x 为此刻 x x 的父节点标号,在边 (fax,x) ( f a x , x ) 上新建一个危险值为 w w 的节点 z z , 原
来的边变为 (fax,z) ( f a x , z ) (z,x) ( z , x )
3. 3k 3 k x1x2...xk x 1 x 2 . . . x k 表示一次询问,意义如题面所示。

题解:
虚树,同时用Splay维护dfs序,LCT维护路径和即可。

#include 
using namespace std;
typedef long long LL;

const int RLEN=1<<18|1;
inline char nc() {
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob) ? -1 :*ib++;
}
inline int rd() {
    char ch=nc(); int i=0,f=1;
    while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
    while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
    return i*f;
}
inline void W(LL x) {
    static int buf[50];
    if(!x) {putchar('0'); return;}
    if(x<0) {putchar('-'); x=-x;}
    while(x) {buf[++buf[0]]=x%10; x/=10;}
    while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}

const int N=4e5+50;
const int INF=0x3f3f3f3f;

struct LCT* lct;
struct Splay* splay;

int n,m,cnt,w[N],fa[N],dfn[N];
LL lst;
vector <int> edge[N];

struct Splay {
    struct node;
    static node* null;
    struct node {
        node *lc,*rc,*fa;
        int dep,dep_mn,tag_add,sze;

        inline void add(int v) {
            dep+=v; dep_mn+=v; tag_add+=v;  
        }

        inline void pushdown() {
            if(!tag_add) return;
            (lc!=null) && (lc->add(tag_add),0);
            (rc!=null) && (rc->add(tag_add),0);
            tag_add=0;
        } 

        inline void upt() {
            sze=lc->sze+rc->sze+1;
            dep_mn=min(lc->dep_mn,rc->dep_mn);
            dep_mn=min(dep_mn,dep);
        }

    }Pool[N],*pos[N],*pool=Pool,*rt;

    inline node* newnode(int v) {
        node *t=++pool;
        t->lc=t->rc=t->fa=null;
        t->dep=t->dep_mn=v;
        t->sze=1;
        return t;
    }

    inline bool which(node *x) {return x->fa->lc==x;}

    inline void rotate(node *x) {
        node *y=x->fa, *z=y->fa;
        if(z!=null) ((z->lc==y) ? (z->lc) : (z->rc))=x;
        x->fa=z; y->fa=x;
        if(y->lc==x) {
            node *b=x->rc;
            x->rc=y; y->lc=b;
            if(b!=null) b->fa=y;
        } else {
            node *b=x->lc;
            x->lc=y; y->rc=b;
            if(b!=null) b->fa=y;
        } y->upt(); x->upt();
    }

    inline void splay(node *x,node *tar) {
        static node* stk[N]; static int tl;
        stk[tl=1]=x;
        for(node *y=x; y->fa!=null; y=y->fa) stk[++tl]=y->fa;
        for(int i=tl; i; i--) stk[i]->pushdown();
        while(x->fa!=tar) {
            node *y=x->fa;
            if(y->fa!=tar) {
                if(which(y)==which(x)) rotate(y);
                else rotate(x);
            } rotate(x);
        }
        if(tar==null) rt=x;
    }

    inline void inc(node *&x,node *fa,node *t) {
        if(x==null) {
            x=t; x->fa=fa; return;
        }
        inc(x->rc,x,t);
    }

    inline void dfs(int x,int f) {
        pos[x]=newnode(f ? pos[f]->dep+1 : 1);
        inc(rt,null,pos[x]); 
        splay(pos[x],null);
        for(auto v:edge[x]) 
            if(v!=f) dfs(v,x);
    }

    inline void init() {
        null=Pool; rt=null;
        null->lc=null->rc=null->fa=null;
        null->dep_mn=null->dep=INF;
        for(int i=2;i<=n;i++)
            edge[fa[i]].push_back(i);
        inc(rt,null,newnode(0));
        dfs(1,0);
        inc(rt,null,newnode(0));
        splay(pool,null);
    }

    inline void set(int x,int f) {
        splay(pos[f],null);
        pos[x]=newnode(pos[f]->dep+1);
    }

    inline node* suf_rt() {
        node *p=rt->rc;
        while(p->lc!=null) p->pushdown(), p=p->lc;
        return p;
    }

    inline void link(int x,int f) {
        splay(pos[f],null);
        splay(suf_rt(),rt);
        rt->rc->lc=pos[x];
        pos[x]->fa=rt->rc;
        rt->rc->upt();
        rt->upt();
    }

    inline int get_dfn(int x) {
        splay(pos[x],null);
        return pos[x]->lc->sze;
    }

    inline node* get_pre(int x) {
        splay(pos[x],null);
        node *p=pos[x]->lc;
        while(p->rc!=null) p->pushdown(), p=p->rc;
        return splay(p,null), p;
    }

    inline node* get_nxt(int x) {
        splay(pos[x],null); 
        int lim=pos[x]->dep;
        node *p=pos[x]->rc;
        while(p!=null) {
            p->pushdown();
            if(p->lc->dep_mn<=lim) p=p->lc;
            else if(p->dep<=lim) break;
            else p=p->rc;
        }
        return splay(p,null), p;
    }

    inline void modify(int now,int x) {
        node *pre=get_pre(x);
        node *nxt=get_nxt(x);
        splay(pre,null); 
        splay(nxt,rt);
        pre->rc->lc->add(-1);
        splay(pos[x],rt);
        pos[now]->fa=pos[x];
        pos[x]->lc=pos[now];
        pos[x]->upt(); 
        rt->upt();
    }

    inline int get_dep(int x) {
        splay(pos[x],null);
        return pos[x]->dep;
    }
};

Splay::node* Splay::null;

struct LCT {
    struct node;
    static node* null;
    struct node {
        node *lc,*rc,*fa;
        int v; LL sum;
        inline void upt() {
            sum=lc->sum+rc->sum+v;
        }
    }Pool[N],*pos[N],*pool=Pool;

    inline node* newnode(int v) {
        node *t=++pool;
        t->lc=t->rc=t->fa=null;
        t->v=t->sum=v;
        return t;
    }

    inline bool isroot(node *x) {return x->fa->lc!=x && x->fa->rc!=x;}
    inline bool which(node *x) {return x->fa->lc==x;}

    inline void rotate(node *x) {
        node *y=x->fa, *z=y->fa;
        if(!isroot(y)) ((z->lc==y) ? z->lc : z->rc)=x;
        x->fa=z; y->fa=x;
        if(y->lc==x) {
            node *b=x->rc;
            x->rc=y; y->lc=b;
            if(b!=null) b->fa=y;
        } else {
            node *b=x->lc;
            x->lc=y; y->rc=b;
            if(b!=null) b->fa=y;
        } y->upt(); x->upt();
    }

    inline void splay(node *x) {
        while(!isroot(x)) {
            node *y=x->fa;
            if(!isroot(y)) {
                if(which(y)==which(x)) rotate(y);
                else rotate(x);
            } rotate(x);
        }   
    }

    inline int access(node *x) {
        node *lst=x;
        for(node *y=null; x!=null; y=x, x=x->fa) {
            lst=x; splay(x); 
            x->rc=y; x->upt();
        }   
        return lst-Pool;
    }

    inline void init() {
        null=Pool; null->lc=null->rc=null->fa=null;
        for(int i=1;i<=n;i++)
            pos[i]=newnode(w[i]);
        for(int i=2;i<=n;i++)
            pos[i]->fa=pos[fa[i]];
    }

    inline void link(int x,int f) {
        splay(pos[x]);
        pos[x]->fa=pos[f];  
    }

    inline void cut(int x,int f) {
        access(pos[f]); splay(pos[x]);
        pos[x]->fa=null;    
    }

    inline int get_lca(int x,int y) {
        access(pos[x]);
        return access(pos[y]);  
    }

    inline void set(int x,int ww) {pos[x]=newnode(ww);}

    inline LL get_sum(int x,int f) {
        LL rs=0;
        access(pos[x]); splay(pos[x]);
        rs+=pos[x]->sum;
        access(pos[f]); splay(pos[f]);
        rs-=pos[f]->sum;
        return rs;
    }
};

LCT::node* LCT::null;

inline int decode(int v) {return (v+lst)%cnt+1;}

int main() {
    splay=new Splay;
    lct=new LCT;
    n=rd(), m=rd(), cnt=n;
    for(int i=1;i<=n;i++) w[i]=rd();
    for(int i=2;i<=n;i++) fa[i]=rd();
    lct->init(); 
    splay->init();
    for(int T=1; T<=m; T++) {
        int op=rd();
        if(op==1) {
            int x=decode(rd()), ww=rd(); ++cnt;
            fa[cnt]=x;

            lct->set(cnt,ww);
            lct->link(cnt,x);

            splay->set(cnt,x);
            splay->link(cnt,x);
        } else if(op==2) {
            int x=decode(rd()), ww=rd(); ++cnt;
            int f=fa[x];

            lct->set(cnt,ww);
            lct->cut(x,f);
            lct->link(cnt,f);
            lct->link(x,cnt);

            splay->set(cnt,f);
            splay->modify(cnt,x);

            fa[cnt]=f; fa[x]=cnt;   
        } else {
            static int stk[N],tl,vir_point[N*2],vc,vir_fa[N];
            vc=rd();
            for(int i=1;i<=vc;i++) 
                vir_point[i]=decode(rd());
            vir_point[++vc]=1;
            for(int i=1;i<=vc;i++)
                dfn[vir_point[i]]=splay->get_dfn(vir_point[i]);
            sort(vir_point+1, vir_point+vc+1, [](int x,int y){return dfn[x]for(int i=vc;i>1;i--) 
                vir_point[++vc]=lct->get_lca(vir_point[i],vir_point[i-1]);
            for(int i=1;i<=vc;i++) {
                int u=vir_point[i];
                dfn[u]=splay->get_dfn(u);
                vir_fa[u]=0;
            }

            sort(vir_point+1, vir_point+vc+1, [](int x,int y){return dfn[x]1,vir_point+vc+1)-vir_point-1;

            stk[tl=1]=vir_point[1];
            for(int i=2;i<=vc;i++) {
                int u=vir_point[i];
                int lca=lct->get_lca(stk[tl],u);
                while(stk[tl]!=lca) --tl;
                vir_fa[u]=lca; stk[++tl]=u;
            }

            lst=0;
            for(int i=1;i<=vc;i++) {
                int u=vir_point[i];
                if(vir_fa[u]) 
                    lst+=lct->get_sum(u,vir_fa[u]);
            }
            lst+=w[1];
            W(lst); putchar('\n');
        }
    }
}

你可能感兴趣的:(虚树,动态树)