zoukankan      html  css  js  c++  java
  • Luogu3348 [ZJOI2016]大森林

    Link

    Solution

    首先不能看错题。题目里有句话:子节点的标号为上一个 0 号操作叶子标号加 1

    它是站在全局0号操作的角度的,比如上一次在([l_0,r_0])长了一个编号为(i)的节点,这一次0操作是在([l,r]),那么长出的节点应该是(i+1)。这样意味着某个编号的节点只有它那一轮操作的([l,r])范围内的树有。也就是说每棵树终态节点编号是不一定连续的。

    而我把它理解成了这棵树中上一次0号操作的标号......(这种错误理解下每棵树终态节点编号都是连续的)。而且样例居然刚好契合这种理解!吐了

    正确理解了题意后,就会好做一些。有几个性质:

    • 因为编号为(i)的节点只在第(i-1)轮0号操作出现,而且保证询问是合法的(询问树上有的节点)。所以可以把每次操作的([l,r])扩展成([1,n])
    • 可以发现1号操作换生长节点并不会影响树的结构。也就是说每个0号操作只受时间在它之前的1号操作的影响。它一定接在它前面离它最近的在该树生效的,1号操作的生长节点下面。

    维护每棵树的形态显然是不行的。考虑从左往右遍历第1棵到第n棵树,发现两棵树之间的变化实际上就是插入、删除一些0,1号操作。所以可以维护两棵树之间的变化,即已经有第(i-1)棵树,想办法把它变成第(i)棵树。

    所以现在要考虑的问题是快速修改连边情况,可以用LCT+虚点来维护。

    先构造图:

     1.对全局的每个1操作按时间顺序建立虚点。每个虚点连向前一个虚点。第一个虚点连向1号实点,1号实点是定根。

     2.把0操作生成的实点连向时间上离它最近的那个1操作虚点(每个实点看作全局生成,不再是[l,r])。

    对于每个1操作,如果它在当前节点生效,那就把它连向对应的生长节点;如果失效,就连向前一个虚点。

    这样的话更换生长节点,修改一下虚点的连边就可以转移所有实点的连边。

    因为不能每次都遍历所有1操作看是否生效,所以可以考虑差分,让其在(l)生效,在(r+1)失效。

    还有一个问题是求两点之间路径长度不能在(split)出来了,因为这样需要(makeroot),但是维护的是有根树,直接(makeroot)会破坏原树结构。

    还是考虑差分。答案是(dis[a]+dis[b]-2 imes dis[lca(a,b)])

    (dis)是到根节点路径,可以(access,splay)来求。

    (lca)同样可以在(LCT)上求出!考虑先(access(a)),那么(a)到根的路径已经在一棵(splay)中了。这时再(access(b)),那么到达根所在的(splay)时经过的那条虚边,指向的父节点,就是(lca(a,b))

    inline int access(int x){
    		int y=0;
    		for(;x;y=x,x=fa[x])
    			splay(x),ch[x][1]=y,pushup(x);
    		return y;
    	}
    

    (access(a))之后再(access(b)),最后的那个(y)

    Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define REP(i,a,b) for(int i=(a),ed=(b);i<=ed;++i)
    inline int read(){
    	register int x=0,f=1;register char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
    	while(isdigit(ch)){x=x*10+(ch^'0');ch=getchar();}
    	return f?x:-x;
    }
    
    const int M=2e5+10,_=M<<1;
    int n,m,rp,vp,L[M],R[M],cnt,ans[M],ans_cnt;
    struct Squery{int type,p,x,y,id;inline bool operator<(const Squery &a)const{return p==a.p?type<a.type:p<a.p;}}q[_];
    
    namespace LCT{
    	int fa[_],ch[_][2],s[_],v[_];
    	inline void pushup(int x){s[x]=s[ch[x][0]]+s[ch[x][1]]+v[x];}
    	inline int getdir(int x){return x==ch[fa[x]][1];}
    	inline bool noroot(int x){return x==ch[fa[x]][0]||x==ch[fa[x]][1];}
    	inline void rotate(int x){
    		int f=fa[x],p=fa[f],k=getdir(x),s=ch[x][!k];
    		ch[x][!k]=f;ch[f][k]=s;if(noroot(f))ch[p][getdir(f)]=x;
    		fa[f]=x;fa[x]=p;if(s)fa[s]=f;
    		pushup(f);
    	}
    	inline void splay(int x){
    		for(int f=fa[x];noroot(x);rotate(x),f=fa[x])
    			if(noroot(f))rotate(getdir(f)==getdir(x)?f:x);
    		pushup(x);
    	}
    	inline int access(int x){
    		int y=0;
    		for(;x;y=x,x=fa[x])
    			splay(x),ch[x][1]=y,pushup(x);
    		return y;
    	}
    	inline void cut(int x){
    		access(x);splay(x);
    		ch[x][0]=fa[ch[x][0]]=0;
    		pushup(x);
    	}
    	inline void link(int x,int y){
    		access(x);splay(x);fa[x]=y;
    	}
    }using namespace LCT;
    
    int main(){
    	n=read(),m=read();vp=m;
    	L[1]=1,R[1]=n;
    	link(++vp,++rp);
    	REP(t,1,m){
    		int op=read();
    		if(!op){
    			++rp;L[rp]=read(),R[rp]=read();v[rp]=1;
    			link(rp,vp);
    		}
    		else if(op==1){
    			int l=read(),r=read(),x=read();
    			l=max(l,L[x]),r=min(r,R[x]);
    			if(l>r)continue;
    			++vp;link(vp,vp-1);
    			q[++cnt]=(Squery){0,l,vp,x,0};
    			q[++cnt]=(Squery){0,r+1,vp,vp-1,0};
    		}
    		else{
    			int x=read(),u=read(),v=read();
    			q[++cnt]=(Squery){1,x,u,v,++ans_cnt};
    		}
    	}
    	sort(q+1,q+cnt+1);
    	REP(t,1,cnt){
    		if(q[t].type){
    			int res=0,x=q[t].x,y=q[t].y,p;
    			access(x);splay(x);res+=s[x];
    			p=access(y);splay(y);res+=s[y];
    			access(p);splay(p);res-=s[p]*2;
    			ans[q[t].id]=res;
    		}
    		else{
    			cut(q[t].x);link(q[t].x,q[t].y);
    		}
    	}
    	REP(i,1,ans_cnt)printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    2018-2019-1 20165227 20165228 20165237 实验五 通讯协议设计
    2018-2019-1 20165227 20165228 20165237 实验四 外设驱动程序设计
    2018-2019-1 20165237 20165227 20165228 实验三 实时系统
    2018-2019-1 20165237 《信息安全系统设计基础》第七周学习总结
    2018-2019-1 20165227 20165228 20165237 实验二 固件程序设计
    2018-2019-1 20165237 《信息安全系统设计基础》第六周学习总结
    2018-2019-1 20165237 《信息安全系统设计基础》第五周学习总结
    2018-2019-1 20165237 《信息安全系统设计基础》第四周学习总结
    2018-2019-1 20165228 20165237 20165227 实验一 开发环境的熟悉
    20165237 2018-2019-1《信息安全系统设计基础》第三周学习总结
  • 原文地址:https://www.cnblogs.com/fruitea/p/12144834.html
Copyright © 2011-2022 走看看