动态树 习题篇
练习#
P3203 [HNOI2010]弹飞绵羊#
思路:
我们假设弹飞就是弹到装置
那么显然这道题就转变为:
对于每个点 都有一个值 ,若是 则 连一条边,否则 连一条边
每次会修改一个点的 或询问 会经过多少个点 (不包括 )
显然我们需要支持动态加边,动态删边,以及查询一段路径上的点的个数
很容易想到可以用 来维护
我们通过 和 来完成修改操作
通过 + 维护 中每个节点的子树大小来完成查询操作
最后输出的就是经过 操作后的
这样就能能够解决此题
话说貌似好像可以用分块硬搞
#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] 洞穴勘测#
思路:
我们需要维护三个操作:连边,删边,判断两点是否连通
显然可以用 维护
我们只需要 ,,以及判断 是否等于 就可以解决此题
#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);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现