ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

动态树 $\text{LCT}$ 习题篇

2022-07-24 17:03:53  阅读:164  来源: 互联网

标签:LCT ch int text read while 习题


目录

\(\text{LCT}\) 练习

P3203 [HNOI2010]弹飞绵羊

思路

我们假设弹飞就是弹到装置 \(\text{n+1}\)

那么显然这道题就转变为:

对于每个点 \(i\) 都有一个值 \(k_i\),若是 \(i+k_i>n\) 则 \(i\to n+1\) 连一条边,否则 \(i\to i+k_i\) 连一条边

每次会修改一个点的 \(k_i\) 或询问 \(i\to n+1\) 会经过多少个点 (不包括 \(n+1\))

显然我们需要支持动态加边,动态删边,以及查询一段路径上的点的个数

很容易想到可以用 \(\text{LCT}\) 来维护

我们通过 \(\text{link(x,y)}\) 和 \(\text{cut(x,y)}\) 来完成修改操作

通过 \(\text{split(x,n+1)}\) + 维护 \(\text{splay}\) 中每个节点的子树大小来完成查询操作

最后输出的就是经过 \(\text{split}\) 操作后的 \(\text{size[n+1]-1}\)

这样就能能够解决此题

话说貌似好像可以用分块硬搞 \(\text{qwq}\)

#include<bits/stdc++.h>
using namespace std;

const int N=2e5+5;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int n,m;
int st[N],a[N];
int f[N],ch[N][2],sz[N],lz[N];

namespace LCT{
	#define l(x) ch[x][0]
	#define r(x) ch[x][1]
	inline void push_up(int x){
		sz[x]=1;
		if(l(x)) sz[x]+=sz[l(x)];
		if(r(x)) sz[x]+=sz[r(x)];	
	}
	inline bool rootful(int x){return l(f[x])!=x&&r(f[x])!=x;}
	inline bool chk(int x){return x==r(f[x]);}
	inline void rev(int x){swap(l(x),r(x)),lz[x]^=1;}
	inline void push_down(int x){
		if(!lz[x]) return;
		if(l(x)) rev(l(x));
		if(r(x)) rev(r(x));
		lz[x]=0;
	}
	inline void rotate(int x){
		int y=f[x],z=f[y],k=chk(x),w=ch[x][k^1];
		if(!rootful(y)) ch[z][chk(y)]=x;f[x]=z;
		if(w) f[w]=y;ch[y][k]=w;
		ch[x][k^1]=y,f[y]=x;
		push_up(y),push_up(x);
	}
	inline void splay(int x){
		int y=x,top=0,z;
		for(st[++top]=y;!rootful(y);st[++top]=y=f[y]);
		for(;top;push_down(st[top--]));
		while(!rootful(x)){
			y=f[x],z=f[y];
			if(!rootful(y))
				rotate(chk(x)==chk(y)?y:x);
			rotate(x);
		}
	}
	inline void access(int x){
		for(int y=0;x;x=f[y=x]){
			splay(x);
			r(x)=y;
			push_up(x);
		}
	}
	inline void makeroot(int x){
		access(x);
		splay(x);
		rev(x);
	}
	inline int findroot(int x){
		access(x);splay(x);
		for(;l(x);x=l(x)) push_down(x);
		splay(x);
		return x;
	}
	inline void link(int x,int y){
		makeroot(x);
		if(findroot(y)!=x) f[x]=y;
	}
	inline void cut(int x,int y){
		makeroot(x);
		if(findroot(y)==x&&f[y]==x&&!l(y)){
			f[y]=r(x)=0;
			push_up(x);
		}
	}
	inline void split(int x,int y){
		makeroot(x);
		access(y);
		splay(y);
	}
	inline int query(int x,int y){
		split(x,y);
		return sz[y];
	}
}

signed main(){
	n=read();
	for(int i=1;i<=n;++i){
		a[i]=read();
		LCT::link(i,i+a[i]>n?n+1:i+a[i]);
	}
	m=read();
	while(m--){
		int op=read(),x=read()+1,y;
		if(op==1) printf("%d\n",LCT::query(x,n+1)-1);
		else{
			y=read();
			LCT::cut(x,x+a[x]>n?n+1:x+a[x]);
			a[x]=y;
			LCT::link(x,x+a[x]>n?n+1:x+a[x]);
		}
	}
}

P2147 [SDOI2008] 洞穴勘测

思路

我们需要维护三个操作:连边,删边,判断两点是否连通

显然可以用 \(\text{LCT}\) 维护

我们只需要 \(\text{link(x,y)}\),\(\text{cut(x,y)}\),以及判断 \(\text{findroot(x)}\) 是否等于 \(\text{findroot(y)}\) 就可以解决此题

#include<bits/stdc++.h>
using namespace std;

const int N=5e5+5;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int n,m,top;
int ch[N][2],f[N],lz[N],st[N];

namespace LCT{
	#define l(x) ch[x][0]
	#define r(x) ch[x][1]
	inline bool rootful(int x){return r(f[x])!=x&&l(f[x])!=x;}
	inline int chk(int x){return x==r(f[x]);}
	inline void rev(int x){swap(l(x),r(x));lz[x]^=1;}
	inline void push_down(int x){
		if(!lz[x]) return;
		if(l(x)) rev(l(x));
		if(r(x)) rev(r(x));
		lz[x]=0;
	}
	inline void rotate(int x){
		int y=f[x],z=f[y],k=chk(x),w=ch[x][k^1];
		if(!rootful(y)) ch[z][chk(y)]=x;f[x]=z;
		if(w) f[w]=y;ch[y][k]=w;
		ch[x][k^1]=y,f[y]=x;
	}
	inline void splay(int x){
		int y=x,top=0,z;
		for(st[++top]=y;!rootful(y);st[++top]=y=f[y]);
		for(;top;push_down(st[top--]));
		while(!rootful(x)){
			y=f[x],z=f[y];
			if(!rootful(y))
				rotate(chk(x)==chk(y)?y:x);
			rotate(x);
		}
	}
	inline void access(int x){
		for(int y=0;x;x=f[y=x]){
			splay(x);
			r(x)=y;
		}
	}
	inline void makeroot(int x){
		access(x);
		splay(x);
		rev(x);
	}
	inline int findroot(int x){
		access(x);splay(x);
		for(;l(x);x=l(x)) push_down(x);
		splay(x);
		return x;
	}
	inline void link(int x,int y){
		makeroot(x);
		if(findroot(y)!=x) f[x]=y;
	}
	inline void cut(int x,int y){
		makeroot(x);
		if(findroot(y)==x&&f[y]==x&&!l(y))
			f[y]=r(x)=0;
	}
	inline int query(int x,int y){
		return findroot(x)==findroot(y);
	}
}

signed main(){
	n=read(),m=read();
	while(m--){
		char s[20];
		scanf("%s",s);
		int x=read(),y=read();
		if(s[0]=='Q') puts(LCT::query(x,y)?"Yes":"No");
		if(s[0]=='C') LCT::link(x,y);
		if(s[0]=='D') LCT::cut(x,y);
	}
}

标签:LCT,ch,int,text,read,while,习题
来源: https://www.cnblogs.com/into-qwq/p/16514835.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有