zoukankan      html  css  js  c++  java
  • bzoj 3153: Sone1 Toptree

    3153: Sone1

    Time Limit: 40 Sec  Memory Limit: 256 MB
    Submit: 511  Solved: 202
    [Submit][Status][Discuss]

    Description

    Sxyz里有一群sx。
    在花老师的指导下,每周4都有一个集会活动,俗称“浇水”活动。
    为了让花老师开花,这群sx都很努力地发言。
    一次xbj对树很关心,总想有一道树的好题目
    所以大家就开始讨论有什么树的好操作。
    为了让题目变的简单,花老师开始就规定了是有根树。
     
    何其蛙:子树修改,加一个数什么的,显然是可做的。
    Dj:换根不是超开心?
    Dd:什么子树min,max也不错啊。
    Zzw:链上询问min也放进去吧。
    Wyk: 链max当然的吧。
    Xbj:如果不能换父亲就太无聊了吧。
    Gy:链加。
    Monkey:链上和。
    Shjj:链上修改。
    Wtd:子树加。
    Sone: 在线就不说什么了吧...
    .............
     
    最后大家发现有这道题目有点麻烦..都懒得写,又由于sone最近被3083的遥远的国度中lct被树剖虐暴了..就担任了出题活动.......

    Input

    第一行是N和M,表示有这棵树有N个点M个询问
    然后是N-1行,每行x,y表示x-y有一条边
    接下去是N行,每行是一个数字,表示每个点的权值
    后面一行表示根
    接下来是M行
    第一个数字是K
    K=0 表示子树修改,后面x,y,表示以x为根的子树的点权值改成y
    K=1 表示换根,后面x,表示把这棵树的根变成x
    K=2 表示链修改,后面x,y,z,表示把这棵树中x-y的路径上点权值改成z
    K=3 表示子树询问min,后面x,表示以x为根的子树中点的权值min
    K=4 表示子树询问max,后面x,表示以x为根的子树中点的权值max
    K=5 表示子树加,后面x,y,表示x为根的子树中点的权值+y
    K=6 表示链加,后面x,y,z,表示把这棵树中x-y的路径上点权值改成+z
    K=7 表示链询问min,后面x,y,表示把这棵树中x-y的路径上点的min
    K=8 表示链询问max,后面x,y,表示把这棵树中x-y的路径上点的max
    K=9 表示换父亲,后面x,y,表示把x的父亲换成y,如果y在x子树里不操作。
    K=10 表示链询问sum,后面x,y,z,表示表示把这棵树中x-y的路径上点的sum
    K=11 表示子树询问sum,后面x,表示以x为根的子树的点权sum
    Output
    对于每个询问输出一个答案。
    Sample Input
    Input1:
    5 5
    2 1
    3 1
    4 1
    5 2
    4
    1
    4
    1
    2
    1
    10 2 3
    3 1
    7 3 4
    6 3 3 2
    9 5 1
     
    Input2:
    10 12
    2 1
    3 2
    4 2
    5 3
    6 4
    7 5
    8 2
    9 4
    10 9
    791
    868
    505
    658
    860
    623
    393
    717
    410
    173
    4
    0 8 800
    1 4
    2 8 2 103
    3 9
    4 4
    5 7 304
    6 8 8 410
    7 10 8
    8 1 8
    9 6 9
    10 2 3
    11 5
     
    Sample Output
     
     
    Output1:
    9
    1
    1
    Output2:
    173
    860
    103
    791
    608
    1557
     
     
     
    数据范围:
    N,M<=100000
    中间所有的值计算在c++的int内

      APIO期间由于实在无聊开的神坑题,从APIO开始到闭幕4天时间,终于把这道题给干掉了。

      Toptree是什么?我咋知道。某日yy出某方法,即把LCT的一个节点的信息加上其虚边连向的链的信息,一层一层往上就可以统计子树信息了。然后hja告诉我这个就是Toptree,只不过如果虚边用链表存会被菊花图卡掉。改成平衡树维护即可。

      确实不难嘛,就是lct再加一个平衡树。

      然后我就SB的用SBT来作为平衡树,然而我并没有写过SBT的标记下放。即SBT在rotate函数中也需要调用down(),就这个问题调了我一天的时间。另外标记到底是什么的问题同样调了一天,最后一天的时间解决的问题只有在n>=10的时候才会出现,大概是当一个结点不存在虚边,那么我们就不能在赋值时改变他的子树信息(因为他根本没有子树)

      对了,运行时间光荣垫底。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cassert>
    using namespace std;
    #define MAXN 100010
    #define MAXT 100010
    #define INF 0x3f3f3f3f
    #ifdef debug
    #define Plog(...) printf(__VA_ARGS__)
    #else
    #define Plog(...) 
    #endif
    int n,m;
    int troot;
    void make_tree(int now,int v);
    void make_chain(int now,int v);
    void make_splus(int now,int v);
    void make_cplus(int now,int v);
    struct toptree_node
    {
            int ch[2];
            int pnt;
            bool rev;
            int val;
            int sroot;
            int splus,cplus,smake,cmake;
            int csum,ssum;
            int cmx,cmn;
            int smx,smn;
            int siz;
            int dsiz;
    }tpt[MAXT];
    int stack[MAXT],tops=-1;
    int topt=0;
    struct SBTree
    {
            int L[MAXT],R[MAXT],S[MAXT],V[MAXT];
            int G[MAXT];
            int vmx[MAXT],vmn[MAXT],sum[MAXT],siz[MAXT],pls[MAXT],mkv[MAXT];
            int stack[MAXN],tops;
            int topt;
            SBTree()
            {
                    tops=-1;
                    topt=0;
                    vmx[0]=-INF;
                    vmn[0]=INF;
            }
            void update(int now)
            {
                    vmx[now]=max(max(tpt[V[now]].cmx,tpt[V[now]].smx),max(vmx[L[now]],vmx[R[now]]));
                    vmn[now]=min(min(tpt[V[now]].cmn,tpt[V[now]].smn),min(vmn[L[now]],vmn[R[now]]));
                    sum[now]=sum[L[now]]+sum[R[now]]+tpt[V[now]].ssum+tpt[V[now]].csum;
                    siz[now]=siz[L[now]]+siz[R[now]]+tpt[V[now]].siz+tpt[V[now]].dsiz;
                    S[now]=S[L[now]]+S[R[now]]+1;
            }
            void Tree_make(int now,int v)
            {
                    mkv[now]=v;
                    sum[now]=v*siz[now];
                    pls[now]=0;
                    vmx[now]=vmn[now]=v;
            }
            void Tree_plus(int now,int delta)
            {
                    vmx[now]+=delta;
                    vmn[now]+=delta;
                    sum[now]+=delta*siz[now];
                    pls[now]+=delta;
            }
            void down(int now)
            {
                    if (mkv[now]!=INF)
                    {
                            Plog("SBT DOWN %d
    ",G[now]);
                            make_tree(V[now],mkv[now]);
                            make_chain(V[now],mkv[now]);
                            if (L[now])Tree_make(L[now],mkv[now]);
                            if (R[now])Tree_make(R[now],mkv[now]);
                            mkv[now]=INF;
                    }
                    if (pls[now])
                    {
                            make_splus(V[now],pls[now]);
                            make_cplus(V[now],pls[now]);
                            if (L[now])Tree_plus(L[now],pls[now]);
                            if (R[now])Tree_plus(R[now],pls[now]);
                            pls[now]=0;
                    }
            }
            void l_rotate(int &now)
            {
                    down(now);//!!!
                    down(R[now]);//!!!
                    int t=R[now];
                    R[now]=L[t];update(now);
                    L[t]=now;update(t);
                    now=t;
            }
            void r_rotate(int &now)
            {
                    down(now);//!!!
                    down(L[now]);//!!!
                    int t=L[now];
                    L[now]=R[t];update(now);
                    R[t]=now;update(t);
                    now=t;
            }
            void maintain(int &now)
            {
                    if (S[L[L[now]]]>S[R[now]])
                    {
                            r_rotate(now);
                            maintain(L[now]);
                            maintain(R[now]);
                            maintain(now);
                    }
                    if (S[R[R[now]]]>S[L[now]])
                    {
                            l_rotate(now);
                            maintain(L[now]);
                            maintain(R[now]);
                            maintain(now);
                    }
                    if (S[L[R[now]]]>S[L[now]])
                    {
                            r_rotate(R[now]);
                            l_rotate(now);
                            maintain(L[now]);
                            maintain(R[now]);
                            maintain(now);
                    }
                    if (S[R[L[now]]]>S[R[now]])
                    {
                            l_rotate(L[now]);
                            r_rotate(now);
                            maintain(R[now]);
                            maintain(L[now]);
                            maintain(now);
                    }
            }
            void Insert(int &now,int val,int id)
            {
                    if (!now)
                    {
                            if (tops==-1)
                                    now=++topt;
                            else
                                    now=stack[tops--];
                            L[now]=R[now]=0;
                            V[now]=val;
                            G[now]=id;
                            mkv[now]=INF;
                            pls[now]=0;
                            update(now);
                            return ;
                    }
                    assert(val!=V[now]);
                    down(now);
                    if (val<V[now])
                            Insert(L[now],val,id);
                    else 
                            Insert(R[now],val,id);
                    update(now);
                    maintain(now);
            }
            void Erase(int &now,int val)
            {
                    assert(now);
                    down(now);
                    if (val==V[now])
                    {
                            if (!L[now])
                            {
                                    stack[++tops]=now;
                                    now=R[now];
                                    //if (now)update(now);
                            }else if (!R[now])
                            {
                                    stack[++tops]=now;
                                    now=L[now];
                                    //if (now)update(now);
                            }else
                            {
                                    l_rotate(now);
                                    Erase(L[now],val);
                                    update(now);
                                    maintain(now);
                            }
                            return ;
                    }
                    if (val<V[now])
                            Erase(L[now],val);
                    else
                            Erase(R[now],val);
                    update(now);
                    maintain(now);
            }
            int Find(int &now,int val)
            {
                    assert(now);
                    if (val==V[now])
                    {
                            down(now);
                            return now;
                    }
                    down(now);
                    if (val<V[now])
                            return Find(L[now],val);
                    else
                            return Find(R[now],val);
            }
            void Scan(int now)
            {
                    if (!now)return ;
                    Scan(L[now]);
                    printf("%d[%d] ",V[now],mkv[now]);
                    Scan(R[now]);
            }
    }SBT;
    bool is_root(int now)
    {
            return !tpt[now].pnt || (tpt[tpt[now].pnt].ch[0]!=now && tpt[tpt[now].pnt].ch[1]!=now);
    }
    void update(int now)
    {
            tpt[now].cmx=max(tpt[now].val,max(tpt[tpt[now].ch[0]].cmx,tpt[tpt[now].ch[1]].cmx));
            tpt[now].cmn=min(tpt[now].val,min(tpt[tpt[now].ch[1]].cmn,tpt[tpt[now].ch[0]].cmn));
            tpt[now].csum=tpt[now].val+tpt[tpt[now].ch[0]].csum+tpt[tpt[now].ch[1]].csum;
    
            tpt[now].smx=max(SBT.vmx[tpt[now].sroot],
                            max(tpt[tpt[now].ch[0]].smx,tpt[tpt[now].ch[1]].smx));
            tpt[now].smn=min(SBT.vmn[tpt[now].sroot],
                            min(tpt[tpt[now].ch[1]].smn,tpt[tpt[now].ch[0]].smn));
            tpt[now].ssum=SBT.sum[tpt[now].sroot]+
                    tpt[tpt[now].ch[0]].ssum+tpt[tpt[now].ch[1]].ssum;
    
            tpt[now].siz=SBT.siz[tpt[now].sroot]+tpt[tpt[now].ch[0]].siz+tpt[tpt[now].ch[1]].siz;
            tpt[now].dsiz=1+tpt[tpt[now].ch[0]].dsiz+tpt[tpt[now].ch[1]].dsiz;
    }
    void make_reverse(int now)
    {
            tpt[now].rev^=1;
            swap(tpt[now].ch[0],tpt[now].ch[1]);
    }
    void make_tree(int now,int v)
    {
            tpt[now].smake=v;
            tpt[now].splus=0;
            //printf("Make Tree:%d %d
    ",now,v);
            if (tpt[now].siz)
            {
                    if (tpt[now].sroot)SBT.Tree_make(tpt[now].sroot,v);
                    tpt[now].smx=tpt[now].smn=v;
                    tpt[now].ssum=v*tpt[now].siz;
            }
    }
    void make_splus(int now,int v)
    {
            tpt[now].splus+=v;
            tpt[now].ssum+=v*tpt[now].siz;
            tpt[now].smx+=v;
            tpt[now].smn+=v;
            if (tpt[now].sroot)
                    SBT.Tree_plus(tpt[now].sroot,v);
    }
    void make_chain(int now,int v)
    {
            tpt[now].val=v;
            tpt[now].cmake=v;
            tpt[now].cplus=0;
            tpt[now].cmx=tpt[now].cmn=v;
            tpt[now].csum=v*tpt[now].dsiz;
    }
    void make_cplus(int now,int v)
    {
            tpt[now].val+=v;
            tpt[now].cplus+=v;
            tpt[now].cmx+=v;
            tpt[now].cmn+=v;
            tpt[now].csum+=v*tpt[now].dsiz;
    }
    
    void down(int now)
    {
            if (tpt[now].rev)
            {
                    if (tpt[now].ch[0])make_reverse(tpt[now].ch[0]);
                    if (tpt[now].ch[1])make_reverse(tpt[now].ch[1]);
                    tpt[now].rev=0;
            }
            if (tpt[now].smake!=INF)
            {
                    if (tpt[now].ch[0])make_tree(tpt[now].ch[0],tpt[now].smake);
                    if (tpt[now].ch[1])make_tree(tpt[now].ch[1],tpt[now].smake);
                    tpt[now].smake=INF;
            }
            if (tpt[now].splus)
            {
                    if (tpt[now].ch[0])make_splus(tpt[now].ch[0],tpt[now].splus);
                    if (tpt[now].ch[1])make_splus(tpt[now].ch[1],tpt[now].splus);
                    tpt[now].splus=0;
            }
            if (tpt[now].cmake!=INF)
            {
                    Plog("TPT DOWN:%d
    ",now);
                    if (tpt[now].ch[0])make_chain(tpt[now].ch[0],tpt[now].cmake);
                    if (tpt[now].ch[1])make_chain(tpt[now].ch[1],tpt[now].cmake);
                    tpt[now].cmake=INF;
            }
            if (tpt[now].cplus)
            {
                    if (tpt[now].ch[0])make_cplus(tpt[now].ch[0],tpt[now].cplus);
                    if (tpt[now].ch[1])make_cplus(tpt[now].ch[1],tpt[now].cplus);
                    tpt[now].cplus=0;
            }
    }
    void rotate(int now)
    {
            int p=tpt[now].pnt,anc=tpt[p].pnt;
            int dir=tpt[p].ch[0]==now;
            if (!is_root(p))
                    tpt[anc].ch[tpt[anc].ch[1]==p]=now;
            tpt[now].pnt=anc;
            tpt[tpt[now].ch[dir]].pnt=p;
            tpt[p].ch[1-dir]=tpt[now].ch[dir];
            tpt[p].pnt=now;
            tpt[now].ch[dir]=p;
            update(p);
            update(now);
    }
    
    
    int get_prv(int now)
    {
            int x=now;
            stack[++tops]=x;
            while (!is_root(x))
            {
                    x=tpt[x].pnt;
                    stack[++tops]=x;
            }
            while (~tops)down(stack[tops--]);
            if (tpt[now].ch[0])
            {
                    now=tpt[now].ch[0];
                    down(now);
                    while (now && tpt[now].ch[1])
                    {
                            now=tpt[now].ch[1];
                            down(now);
                    }
                    return now;
            }else
            {
                    while (now && tpt[tpt[now].pnt].ch[0]==now)
                            now=tpt[now].pnt;
                    now=tpt[now].pnt;
                    return now;
            }
    }
    void splay(int now)
    {
            int x=now;
            stack[++tops]=x;
            while (!is_root(x))
            {
                    x=tpt[x].pnt;
                    stack[++tops]=x;
                    if (x==troot)troot=now;
            }
            if (tpt[x].pnt)
            {
                    int p=tpt[x].pnt;
                    SBT.Erase(tpt[p].sroot,x);
            }
            while (~tops)
                    down(stack[tops--]);
            while (!is_root(now))
            {
                    int p=tpt[now].pnt;
                    int anc=tpt[p].pnt;
                    if (is_root(p))
                            rotate(now);
                    else if ((tpt[anc].ch[0] == p) == (tpt[p].ch[0] == now))
                            rotate(p),rotate(now);
                    else
                            rotate(now),rotate(now);
            }
            if (tpt[now].pnt)
            {
                    int p=tpt[now].pnt;
                    SBT.Insert(tpt[p].sroot,now,p);
            }
    }
    int access(int now)
    {
            int x=now;
            while (x)
            {
                    stack[++tops]=x;
                    x=tpt[x].pnt;
            }
            while (~tops)
            {
                    down(stack[tops]);
                    if (tops && is_root(stack[tops-1]))
                            SBT.Find(tpt[stack[tops]].sroot,stack[tops-1]);
                    tops--;
            }
            int son=0;
            while (now)
            {
                    splay(now);
                    if (son)SBT.Erase(tpt[now].sroot,son);
                    if (tpt[now].ch[1])SBT.Insert(tpt[now].sroot,tpt[now].ch[1],now);
                    tpt[now].ch[1]=son;
                    update(now);
                    son=now;
                    now=tpt[now].pnt;
            }
            return son;
    }
    void make_root(int now)
    {
            troot=now;
            make_reverse(access(now));
    }
    void link(int x,int y)
    {
            make_root(x);
            access(x);
            make_root(y);
            access(y);
            tpt[x].pnt=y;
            tpt[y].ch[1]=x;
            update(y);
    }
    void tree_make(int now,int val)
    {
            access(now);
            int t=get_prv(now);
            if (t)splay(t);
            make_tree(now,val);
            make_chain(now,val);
            if (t)update(t);
    }
    void chain_make(int x,int y,int val)
    {
            make_root(x);
            make_chain(access(y),val);
    }
    void tree_plus(int now,int val)
    {
            access(now);
            splay(now);
            int t=get_prv(now);
            if (t)splay(t);
            make_splus(now,val);
            make_cplus(now,val);
            if (t)update(t);
    }
    void chain_plus(int x,int y,int val)
    {
            make_root(x);
            make_cplus(access(y),val);
    }
    int chain_sum(int x,int y)
    {
            make_root(x);
            return tpt[access(y)].csum;
    }
    int chain_max(int x,int y)
    {
            make_root(x);
            return tpt[access(y)].cmx;
    }
    int chain_min(int x,int y)
    {
            make_root(x);
            return tpt[access(y)].cmn;
    }
    int tree_sum(int x)
    {
            access(x);
            int t=get_prv(x);
            if (t)splay(t);
            return tpt[x].ssum+tpt[x].csum;
    }
    int tree_max(int x)
    {
            access(x);
            int t=get_prv(x);
            if (t)splay(t);
            return max(tpt[x].cmx,tpt[x].smx);
    }
    int tree_min(int x)
    {
            access(x);
            int t=get_prv(x);
            if (t)splay(t);
            return min(tpt[x].cmn,tpt[x].smn);
    }
    bool same_tree(int x,int y)
    {
            while (tpt[x].pnt)x=tpt[x].pnt;
            while (tpt[y].pnt)y=tpt[y].pnt;
            return x==y;
    }
    void Scan_chain(int now)
    {
            if (!now)return ;
            down(now);
            Scan_chain(tpt[now].ch[0]);
            printf("%d ",now);
            Scan_chain(tpt[now].ch[1]);
    }
    int edge[MAXN][2];
    void Print()
    {
            printf("-------------------------
    ");
            for (int j=1;j<=n;j++)
            {
                    printf("Node #%d#
    ",j);
                    if (tpt[j].smake==16)printf("Taged
    ");
                    if (!is_root(j))continue;
                    printf("Root :%d
    ",j);
                    printf("TreeA:
    ");
                    Scan_chain(j);
                    printf("
    ");
                    printf("TreeB:
    ");
                    SBT.Scan(tpt[j].sroot);
                    printf("
    ");
                    printf("
    ");
            }
            printf("
    ");
    }
    int main()
    {
            freopen("input.txt","r",stdin);
            //freopen("output.txt","w",stdout);
            int croot;
            scanf("%d%d",&n,&m);
            tpt[0].cmx=tpt[0].smx=-INF;
            tpt[0].cmn=tpt[0].smn=INF;
            int x,y,z;
            for (int i=1;i<n;i++)
            {
                    scanf("%d%d",&x,&y);
                    edge[i][0]=x;
                    edge[i][1]=y;
            }
            for (int i=1;i<=n;i++)
            {
                    scanf("%d",&x);
                    tpt[i].val=x;
                    update(i);
            }
            for (int i=1;i<n;i++)
                    link(edge[i][0],edge[i][1]);
            scanf("%d",&croot);
            int opt;
            int cnt=0;
            for (int i=0;i<m;i++)
            {
                    scanf("%d",&opt);
                    if (opt==0)
                    {
                            scanf("%d%d",&x,&y);
                            make_root(croot);
                            tree_make(x,y);
                    }else if (opt==1)
                    {
                            scanf("%d",&croot);
                    }else if (opt==2)
                    {
                            scanf("%d%d%d",&x,&y,&z);
                            chain_make(x,y,z);
                    }else if (opt==3)
                    {
                            scanf("%d",&x);
                            make_root(croot);
                            cnt++;
                            printf("%d
    ",tree_min(x));
                    }else if (opt==4)
                    {
                            scanf("%d",&x);
                            make_root(croot);
                            cnt++;
                            printf("%d
    ",tree_max(x));
                    }else if (opt==5)
                    {
                            scanf("%d%d",&x,&y);
                            make_root(croot);
                            tree_plus(x,y);
                    }else if (opt==6)
                    {
                            scanf("%d%d%d",&x,&y,&z);
                            chain_plus(x,y,z);
                    }else if (opt==7)
                    {
                            scanf("%d%d",&x,&y);
                            cnt++;
                            printf("%d
    ",chain_min(x,y));
                    }else if (opt==8)
                    {
                            scanf("%d%d",&x,&y);
                            cnt++;
                            printf("%d
    ",chain_max(x,y));
                    }else if (opt==9)
                    {
                            scanf("%d%d",&x,&y);
                            if (croot==x)continue;
                            make_root(croot);
                            access(x);
                            z=get_prv(x);
                            if (z)
                            {
                                    splay(z);
                                    assert(tpt[x].pnt==z);
                                    assert(tpt[z].ch[1]==x);
                                    tpt[z].ch[1]=0;
                                    tpt[x].pnt=0;
                                    update(z);
                            }
                            if (same_tree(x,y))
                            {
                                    link(x,z);
                            }else
                            {
                                    link(x,y);
                            }
                    }else if (opt==10)
                    {
                            scanf("%d %d",&x,&y);
                            cnt++;
                            printf("%d
    ",chain_sum(x,y));
                    }else if (opt==11)
                    {
                            scanf("%d",&x);
                            make_root(croot);
                            cnt++;
                            printf("%d
    ",tree_sum(x));
                    }
                    //    Print();
            }
            return 0;
    }
  • 相关阅读:
    尾递归
    Appium环境搭建
    虚拟机与主机的相互访问,虚拟机访问外网
    Python
    npm i 安装
    redis过期键删除策略
    Redis的过期策略和内存淘汰机制
    redis的两种持久化方案
    JVM 方法内联
    进程/线程/协程
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4496335.html
Copyright © 2011-2022 走看看