BZOJ4573: [Zjoi2016]大森林【LCT+扫描线】

7 篇文章 0 订阅
1 篇文章 0 订阅

4573: [Zjoi2016]大森林

又是一道神仙毒瘤题,我们可以将询问放到最后,这样就可以用扫描线搞了,对于第 i i i棵树,可以从第 i − 1 i-1 i1棵树继承过来,所以我们可以建一棵LCT来维护。

但是这题的难点是1操作,对于1操作我们建虚点,让0操作的点连向输入时间最近的虚点,然后虚点之间连边 ( i , i − 1 ) (i,i-1) (i,i1)。每次遇到1操作,断开这个操作原来的虚边,连向实际的节点。但是谁想得到啊!!!

调试调到自闭,最后发现continue跳过了我对答案负的初值QAQ,不过LCT尽然一遍写对了。

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=600005;
int q,L,P1,P2,n,m,cnt,LT[MAXN],RT[MAXN],Ans[MAXN],Tim,Top,a[MAXN];
struct LCT{
	int rev[MAXN],Fa[MAXN],Son[MAXN][2],Siz[MAXN];
	bool IsRoot(int rt){return Son[Fa[rt]][0]!=rt&&Son[Fa[rt]][1]!=rt;}
	bool Get(int rt){return Son[Fa[rt]][1]==rt;}
	void PushUp(int rt){Siz[rt]=Siz[Son[rt][0]]+Siz[Son[rt][1]]+a[rt];}
	void PushDown(int rt){
		if(!rev[rt]) return;
		rev[rt]^=1,rev[Son[rt][0]]^=1,rev[Son[rt][1]]^=1;
		swap(Son[rt][0],Son[rt][1]);
	}
	void Rotate(int x){
		int fa=Fa[x],L=Get(x);
		if(!IsRoot(fa)) Son[Fa[fa]][Get(fa)]=x;
		Fa[x]=Fa[fa],Fa[Son[x][L^1]]=fa,Fa[fa]=x;
		Son[fa][L]=Son[x][L^1],Son[x][L^1]=fa;
		PushUp(fa),PushUp(x);
	}
	void DFS(int x){if(!IsRoot(x)) DFS(Fa[x]);PushDown(x);}
	void Splay(int x){for(DFS(x);!IsRoot(x);Rotate(x)) if(!IsRoot(Fa[x])) Rotate(Get(Fa[x])==Get(x)?Fa[x]:x);}
	void Access(int x){for(int lst=0;x;lst=x,x=Fa[x]) Splay(x),Son[x][1]=lst,PushUp(x);}
	void MakeRoot(int x){Access(x),Splay(x),rev[x]^=1;}
	void Link(int x,int y){MakeRoot(x),Fa[x]=y;}
	void Cut(int x,int y){MakeRoot(x),Access(y),Splay(y),Fa[x]=Son[y][0]=0,PushUp(y);}
	int Ask(int x,int y){MakeRoot(x),Access(y),Splay(y);return Siz[y];}
}T;
struct Seg{
	int p,opt,u,v,t;
	bool operator <(const Seg b)const{return p<b.p||(p==b.p&&opt<b.opt);}
}Line[MAXN];
#include<cctype>
int read(){
	int ret=0;char ch=getchar();bool f=1;
	for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
	for(; isdigit(ch);ch=getchar()) ret=ret*10+ch-48;
	return f?ret:-ret;
}
int main(){
	n=read(),m=read();
	Tim=1;LT[1]=1,RT[1]=n;
	for(int i=1;i<=m;i++){
		Ans[i]=-1;
		int Type=read();
		if(Type==0){
			int L=read(),R=read();LT[++Tim]=L,RT[Tim]=R;
			Line[++Top]=(Seg){L,1,Tim,0,i},Line[++Top]=(Seg){R,5,Tim,0,i};
		}else
		if(Type==1){
			int L=read(),R=read(),k=read();if(k>Tim) continue;
			L=max(LT[k],L),R=min(RT[k],R);if(L>R) continue;
			Line[++Top]=(Seg){L,2,0,k,i},Line[++Top]=(Seg){R,4,0,k,i};
		}else Line[++Top]=(Seg){read(),3,read(),read(),i};
	}
	cnt=Tim+1;
	for(int i=1;i<=Top;i++){
		if(Line[i].opt==1) Line[i].v=cnt;else
		if(Line[i].opt==2) Line[i].u=++cnt;else
		if(Line[i].opt==4) Line[i].u=cnt;else
		if(Line[i].opt==5) Line[i].v=cnt;
	}
	sort(Line+1,Line+1+Top);T.Link(1,Tim+1);
	for(int i=Tim+2;i<=cnt;i++) T.Link(i-1,i);
	for(int i=1;i<=Tim;i++) a[i+cnt]=T.Siz[i+cnt]=1;
	for(int j=1;j<=Top;j++)
	if(Line[j].p){
		if(Line[j].opt==1) T.Link(Line[j].u,Line[j].u+cnt),T.Link(Line[j].u+cnt,Line[j].v);else
		if(Line[j].opt==2) T.Cut(Line[j].u,Line[j].u-1),T.Link(Line[j].v,Line[j].u);else
		if(Line[j].opt==3) Ans[Line[j].t]=T.Ask(Line[j].u,Line[j].v);else
		if(Line[j].opt==4) T.Cut(Line[j].v,Line[j].u),T.Link(Line[j].u,Line[j].u-1);else
		if(Line[j].opt==5) T.Cut(Line[j].u,Line[j].u+cnt),T.Cut(Line[j].u+cnt,Line[j].v);
	}
	for(int i=1;i<=m;i++) if(Ans[i]!=-1) printf("%d\n",Ans[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值