zoukankan      html  css  js  c++  java
  • 【ZJOI2016】大森林

    Description

    给定 (n) 个树,每个树初始的生长点为 (1),需要支持以下操作

    • 生长:让 ([l,r]) 中的树长出来一个其生长点下面的点

    • 修改:更改生长点

    • 查询:求某棵树上两点距离

    (n,Qle 10^5)

    Solution

    考虑题设可以把它们都离线之后统一处理,那么 (trivial) 地用扫描线处理操作

    也就是每棵树先长出来最终形态再回答询问

    对于生长一个节点,直接差分,最后统一做即可

    而对于更换生长点,考虑建立若干虚点表示操作,但是没有点权(真正生长出来的点有点权,为了求 (dis)

    具体而言,一开始求最终方案的时候

    修改 (l,r) 的生长点,先对存在 (x) 号点的区间取交集

    之后让新点和原来的生长点连边,再和新的生长点连边

    在最后的统一处理中把虚点切掉/连上即可

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define For(i,a,b) for(register int i=a;i<=b;++i)
    #define Down(i,a,b) for(register int i=a;i>=b;i--)
    #define reg register
    namespace yspm{
    	inline int read(){
    		int res=0,f=1; char k;
    		while(!isdigit(k=getchar())) if(k=='-') f=-1;
    		while(isdigit(k)) res=res*10+k-'0',k=getchar();
    		return res*f;
    	}
    	const int N=4e5+10;
    	int fa[N],rs[N],ls[N],sum[N],v[N]; 
    	inline int min(int x,int y){return x<y?x:y;}
    	inline int max(int x,int y){return x>y?x:y;}
    	inline void swap(int &x,int &y){int t=x; x=y; y=t; return ;}
    	inline bool isroot(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
    	inline void push_up(int x){sum[x]=sum[ls[x]]+sum[rs[x]]+v[x]; return ;}
    	inline void rotate(int x){
    		int y=fa[x],z=fa[y]; if(!isroot(y)) if(ls[z]==y) ls[z]=x; else rs[z]=x; 
    		if(ls[y]==x) ls[y]=rs[x],fa[rs[x]]=y,rs[x]=y; 
    		else rs[y]=ls[x],fa[ls[x]]=y,ls[x]=y; 
    		fa[x]=z; fa[y]=x; return push_up(y),push_up(x);
    	}
    	inline void splay(int x){
    		while(!isroot(x)){
    			int y=fa[x],z=fa[y]; if(!isroot(y)) rotate((ls[y]==x)^(ls[z]==y)?x:y);
    			rotate(x);
    		} return push_up(x);
    	}
    	struct query{
    		int pos,id,x,y; 
    		bool operator<(const query &a)const{return pos^a.pos?pos<a.pos:id<a.id;}
    	}q[N];
    	inline int access(int x){int y=0; for(;x;x=fa[y=x]) splay(x),rs[x]=y,push_up(x); return y;}
    	inline void cut(int x){access(x); splay(x); ls[x]=fa[ls[x]]=0; push_up(x); return ;}
    	inline void link(int x,int y){splay(x),fa[x]=y; return ;}
    	int L[N],R[N],nd[N],ctq,n,Q,num,st,pos,cnt,ans[N];
    	signed main(){
    		//freopen("1.in","r",stdin); 
    		n=read(); Q=read(); L[1]=1,R[1]=n; num=v[1]=sum[1]=nd[1]=1; link(pos=st=2,1); 
    		for(reg int i=1,x,opt,l,r;i<=Q;++i){
    			opt=read(),l=read(),r=read(); 
    			if(opt==0) link(nd[++num]=++pos,st),v[pos]=sum[pos]=1,L[num]=l,R[num]=r; 
    			else if(opt==1){
    				x=read(),l=max(l,L[x]); r=min(r,R[x]); if(r<l) continue;
    				link(++pos,st); q[++cnt]=(query){l,i-Q,pos,nd[x]}; q[++cnt]=(query){r+1,i-Q,pos,st};
    				st=pos;
    			}else x=read(),q[++cnt]=(query){l,++ctq,nd[r],nd[x]};
    		} 
    		sort(q+1,q+cnt+1); 
    		for(reg int lca,i=1,res;i<=cnt;++i){
    			if(q[i].id>0){
    				res=0; access(q[i].x); splay(q[i].x); res+=sum[q[i].x]; 
    				lca=access(q[i].y); splay(q[i].y); res+=sum[q[i].y];
    				access(lca); splay(lca); ans[q[i].id]=res-2*sum[lca];
    			}else cut(q[i].x),link(q[i].x,q[i].y);
    		}
    		for(reg int i=1;i<=ctq;++i) printf("%lld
    ",ans[i]);
    		return 0;
    	}
    }
    signed main(){return yspm::main();}
    
    
    
  • 相关阅读:
    C# 学习之旅(1)
    SqlServer安装教程
    Aop和Filter区别
    Redis入门
    SpringMVC与Struts2的主要区别
    SpringMVC执行流程
    ssm初始化环境搭建
    Oracle 高效分页
    Oracle 综合:游标和动态SQL
    Oracle 动态SQL
  • 原文地址:https://www.cnblogs.com/yspm/p/14401748.html
Copyright © 2011-2022 走看看