zoukankan      html  css  js  c++  java
  • BZOJ4573:[ZJOI2016]大森林——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=4573

    https://www.luogu.org/problemnew/show/P3348#sub

    http://uoj.ac/problem/195

    https://loj.ac/problem/2092

    小Y家里有一个大森林,里面有n棵树,编号从1到n。一开始这些树都只是树苗,只有一个节点,标号为1。这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力。

    小Y掌握了一种魔法,能让第l棵树到第r棵树的生长节点长出一个子节点。同时她还能修改第l棵树到第r棵树的生长节点。她告诉了你她使用魔法的记录,你能不能管理她家的森林,并且回答她的询问呢?

    参考:http://www.sigongzi.org/index.php/archives/LOJ2092.html

    思路:

    显然我们不能对每棵树LCT维护一下,而且我们对于这棵树的形态还很严格。

    那么我们把前一棵树的形态转换为后一棵树的形态,这样就只需要一棵树了。

    先考虑对于0操作,实际上我们可以记录每个时刻每个节点在哪一段区间中(代码的L和R就是干这个的),所以我们大可以对所有的树都进行0操作。

    对于1操作,和0操作类似,用L和R更新l和r后进行操作。

    然后为了能够快捷的更新树,我们建立一个size为0的虚点(这样对于路径长度就不需要修改了),所有的生长操作都在上面进行,这样我们删除的时候cut这个点即可。

    对于2操作,事实上两个点一定存在的话,完全可以让0和1操作全部排到它的前面。

    实现:

    先把所有操作存下来,然后以操作的树为第一关键字,操作编号和顺序为第二关键字排序。

    (对于区间修改思考差分,毕竟我们都是对同一棵树操作的。)

    然后按树编号从左到右进行操作,对于0和1操作先对虚点清空然后长即可。

    查询的时候就是用LCA求最短路的方法一样。

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cctype>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cmath>
    using namespace std;
    const int N=4e5+5;
    struct data{
        int pos,id,from,to;
    }qry[N];
    int n,m,fa[N],tr[N][2],val[N],size[N];
    int cnt,tot,sum,aux,L[N],R[N],id[N],ans[N];
    inline bool cmp(data a,data b){
        return a.pos<b.pos||(a.pos==b.pos&&a.id<b.id);
    }
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    inline bool get(int x){
        return tr[fa[x]][1]==x;
    }
    inline bool isroot(int x){
        if(!fa[x])return 1;
        return tr[fa[x]][0]!=x&&tr[fa[x]][1]!=x;
    }
    inline void upt(int x){
        size[x]=val[x];
        if(tr[x][0])size[x]+=size[tr[x][0]];
        if(tr[x][1])size[x]+=size[tr[x][1]];
    }
    inline void rotate(int x){
        int y=fa[x],z=fa[y],b=tr[y][0]==x?tr[x][1]:tr[x][0];
        if(z&&!isroot(y))(tr[z][0]==y?tr[z][0]:tr[z][1])=x;
        fa[x]=z;fa[y]=x;b?fa[b]=y:0;
        if(tr[y][0]==x)tr[x][1]=y,tr[y][0]=b;
        else tr[x][0]=y,tr[y][1]=b;
        upt(y);upt(x);
    }
    inline void splay(int x){
        while(!isroot(x)){
        if(!isroot(fa[x]))
            rotate((get(x)==get(fa[x])?fa[x]:x));
        rotate(x);
        }
        upt(x);
    }
    inline int access(int x){
        int y;
        for(y=0;x;y=x,x=fa[x]){
        splay(x);tr[x][1]=y;
        if(y)fa[y]=x;
        }
        return y;
    }
    inline void link(int x,int y){
        splay(y);fa[x]=y;
    }
    inline void cut(int x){
        access(x);splay(x);
        if(tr[x][0])fa[tr[x][0]]=0;
        tr[x][0]=0;upt(x);
    }
    inline void makenode(int x){
        val[++sum]=x;size[sum]=x;
    }
    int main(){
        n=read(),m=read();
        cnt=1;L[cnt]=1,R[cnt]=n;id[cnt]=1;
        makenode(1);makenode(0);
        aux=sum;
        link(aux,id[1]);
        for(int i=1;i<=m;i++){
        int op=read();
        if(op==0){
            L[++cnt]=read(),R[cnt]=read();
            makenode(1);
            id[cnt]=sum;
            qry[++tot]=(data){1,i-m,sum,aux};
        }
        if(op==1){
            int l=read(),r=read(),x=read();
            l=max(l,L[x]);r=min(r,R[x]);
            if(l<=r){
            makenode(0);
            link(sum,aux);
            qry[++tot]=(data){l,i-m,sum,id[x]};
            qry[++tot]=(data){r+1,i-m,sum,aux};
            aux=sum;
            }
        }
        if(op==2){
            int l=read(),u=read(),v=read();
            qry[++tot]=(data){l,i,id[u],id[v]};
        }
        }
        memset(ans,-1,sizeof(ans));
        sort(qry+1,qry+tot+1,cmp);
        for(int i=1,p=1;i<=tot;p++){
        while(qry[i].pos==p){
            if(qry[i].id>0){
            ans[qry[i].id]=0;
            access(qry[i].from);splay(qry[i].from);
            ans[qry[i].id]+=size[qry[i].from];
            int lca=access(qry[i].to);
            splay(qry[i].to);
            ans[qry[i].id]+=size[qry[i].to];
            access(lca);splay(lca);ans[qry[i].id]-=size[lca]*2;
            }
            else{
            cut(qry[i].from);link(qry[i].from,qry[i].to);
            }
            i++;
        }
        }
        for(int i=1;i<=m;i++){
        if(ans[i]>=0)printf("%d
    ",ans[i]);
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

     +本文作者:luyouqi233。               +

     +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    Spring.Net框架与WCF的集成(上)
    重入与回调并发(Reentrant & CallbackConcurrency )
    WCF中的异步实现
    WCF开发时如何选择正确的实例模式(InstanceMode)?
    WCF实例与并发
    WCF消息可靠性与有序传递
    WCF实际应用之IParameterInspector扩展
    WCF中几个基本知识点整理
    HTTP与Tcp协议下双工通信的差异
    细说WCF中的会话模式
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8483154.html
Copyright © 2011-2022 走看看