zoukankan      html  css  js  c++  java
  • bzoj 4573 大森林

    bzoj 4573 大森林

    • 由于树上路径是唯一的,查询合法的两个点间路径长度显然与其他加点操作无关,所以可以离线处理,将所有的查询放在加点后.
    • 这样我们可以对每棵树都在上颗树的基础上处理好形态后,处理这颗树上的询问.
    • 考虑若没有操作 (1) ,则所有树都一模一样.那么两棵树的形态不同,一定是某一颗执行了操作 (1) ,另一个却没有.只需要在每个关键位置(修改开始或结束时)将原来生长点所有子树挂到新的生长点下.
    • 若暴力移动子树,当子树数目较大时就会很劣.可以对每个操作 (1) 建立一个虚点,将这个操作内挂上去的点都挂在虚点上,于是只需要移动虚点就可以了.注意将虚点 (siz) 设置为 (0) .
    • 查询答案时,使用 (dep[x]+dep[y]-2*dep[lca]) 计算,避免虚点造成的影响.
    • 直接用 (split(x,y)) 会出问题.因为你把路径抠出来之后不知道要不要减去 (1) .
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define mp make_pair
    #define pii pair<int,int>
    inline int read()
    {
    	int x=0;
    	bool pos=1;
    	char ch=getchar();
    	for(;!isdigit(ch);ch=getchar())
    		if(ch=='-')
    			pos=0;
    	for(;isdigit(ch);ch=getchar())
    		x=x*10+ch-'0';
    	return pos?x:-x;
    }
    const int MAXN=3e5+10;
    struct query{
    	int pos,op,x,y;
    	bool operator < (const query &rhs) const
    		{
    			return pos==rhs.pos?op<rhs.op:pos<rhs.pos;
    		}
    }q[MAXN];
    namespace LCT{
    	int stk[MAXN],tp;
    	int tot;
    	struct node{
    		int ch[2],fa;
    		int rev;
    		int siz,val;
    		node()
    			{
    				fa=ch[0]=ch[1]=0;
    				rev=0;
    				siz=val=0;
    			}
    	}tree[MAXN];
    	#define root tree[x]
    	#define lson tree[root.ch[0]]
    	#define rson tree[root.ch[1]]
    	inline void pushup(int x)
    		{
    			root.siz=lson.siz+root.val+rson.siz;
    		}
    	void inverse(int x)
    		{
    			swap(root.ch[0],root.ch[1]);
    			root.rev^=1;
    		}
    	void pushdown(int x)
    		{
    			if(root.rev)
    				{
    					if(root.ch[0])
    						inverse(root.ch[0]);
    					if(root.ch[1])
    						inverse(root.ch[1]);
    					root.rev=0;
    				}
    		}
    	bool isroot(int x)
    		{
    			int y=root.fa;
    			return tree[y].ch[0]!=x && tree[y].ch[1]!=x;
    		}
    	void rotate(int x)
    		{
    			int y=tree[x].fa,z=tree[y].fa;
    			int k=tree[y].ch[1]==x;
    			if(!isroot(y))
    				tree[z].ch[tree[z].ch[1]==y]=x;
    			tree[x].fa=z;
    			tree[tree[x].ch[k^1]].fa=y;
    			tree[y].ch[k]=tree[x].ch[k^1];
    			tree[x].ch[k^1]=y;
    			tree[y].fa=x;
    			pushup(y);
    			pushup(x);
    		}
    	void splay(int x)
    		{
    			tp=0;
    			stk[++tp]=x;
    			for(int pos=x;!isroot(pos);pos=tree[pos].fa)
    				stk[++tp]=tree[pos].fa;
    			while(tp)
    				pushdown(stk[tp--]);
    			while(!isroot(x))
    				{
    					int y=tree[x].fa,z=tree[y].fa;
    					if(!isroot(y))
    						(tree[y].ch[0]==x)^(tree[z].ch[0]==y)?rotate(x):rotate(y);
    					rotate(x);
    				}
    			pushup(x);
    		}
    	int Access(int x)
    		{
    			int y;
    			for(y=0;x;y=x,x=tree[x].fa)
    				{
    					splay(x);
    					tree[x].ch[1]=y;
    					pushup(x);
    				}
    			return y;
    		}
    	void makeroot(int x)
    		{
    			Access(x);
    			splay(x);
    			inverse(x);
    		}
    	int findroot(int x)
    		{
    			Access(x);
    			splay(x);
    			while(tree[x].ch[0])
    				x=tree[x].ch[0];
    			return x;
    		}
    	void split(int x,int y)
    		{
    			makeroot(x);
    			Access(y);
    			splay(y);
    		}
    	void Link(int x,int y)
    		{
    			makeroot(x);
    			tree[x].fa=y;
    		}
    	void Cut(int x)
    		{
    			Access(x);
    			splay(x);
    			tree[tree[x].ch[0]].fa=0;
    			tree[x].ch[0]=0;
    			pushup(x);
    		}
    }
    using namespace LCT;
    int solve(int x,int y)
    {
    	int ans=0;
    	Access(x);
    	splay(x);
    	ans+=tree[x].siz;
    	int lca=Access(y);
    	splay(y);
    	ans+=tree[y].siz;
    	Access(lca);
    	splay(lca);
    	ans-=2*tree[lca].siz;
    	return ans;
    }
    void newnode(int v)
    {
    	int x=++tot;
    	root.val=root.siz=v;
    }
    int n,m;
    int last,id[MAXN],idd,cnt,L[MAXN],R[MAXN],qs;
    inline void insq(int pos,int op,int x,int y)
    {
    	++cnt;
    	q[cnt].pos=pos,q[cnt].op=op;
    	q[cnt].x=x,q[cnt].y=y;
    }
    int ans[MAXN];
    int main()
    {
    	tot=0;
    	n=read(),m=read();
    	newnode(1),idd=1,L[1]=1,R[1]=n,id[1]=1;
    	newnode(0),last=2,Link(2,1);
    	for(int i=1;i<=m;++i)
    		{
    			int type=read();
    			if(type==0)
    				{
    					int l=read(),r=read();
    					newnode(1);
    					L[++idd]=l,R[idd]=r,id[idd]=tot;
    					insq(1,i-m,tot,last);
    				}
    			else if(type==1)
    				{
    					int l=read(),r=read(),x=read();
    					l=max(l,L[x]),r=min(r,R[x]);
    					if(l<=r)
    						{
    							newnode(0);
    							Link(tot,last);
    							insq(l,i-m,tot,id[x]);
    							insq(r+1,i-m,tot,last);
    							last=tot;
    						}
    				}
    			else
    				{
    					int x=read(),u=read(),v=read();
    					insq(x,++qs,id[u],id[v]);
    				}
    		}
    	sort(q+1,q+cnt+1);
    	for(int i=1,j=1;i<=n;++i)
    		{
    			for(;j<=cnt && q[i].pos==i;++j)
    				{
    					if(q[j].op<=0)
    						{
    							Cut(q[j].x);
    							Link(q[j].x,q[j].y);
    						}
    					else
    						ans[q[j].op]=solve(q[j].x,q[j].y);
    				}
    		}
    	for(int i=1;i<=qs;++i)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    [转载]pda 和pc 之间的文件操作(利用Microsoft ActiveSync同步文件数据)
    获取XML文件中内容大小
    听猪的“旅行的意义”有感
    If a file is locked, you can wait until the lock times out to redeploy, or s
    七个顶级的心理寓言(转载)
    html table 上下左右边框
    判断浏览器动态加载CSS等内容
    课程表
    input文本框、文字、按钮、图片 垂直居中对齐
    JUnit3
  • 原文地址:https://www.cnblogs.com/jklover/p/10414862.html
Copyright © 2011-2022 走看看