我们可以用一个set维护一下点的大小关系,那么修改只需要查一下前驱后继就行了
然后旋转的话,推一下就可以发现只会影响
f
a
[
x
]
fa[x]
fa[x]的左/右儿子,和
r
o
o
t
root
root的父亲,
那就随便LCT一波,
d
e
p
dep
dep用LCT也很好维护
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=1e5+5;
int a[N];
struct cmp{bool operator()(const int &x,const int &y)const{return a[x]<a[y];}};
set<int,cmp>s;
namespace LCT{
int tot=0,root;
int ls[N],rs[N],fa[N],rev[N],siz[N],L[N],R[N],F[N];
inline void pushup(int x){siz[x]=siz[ls[x]]+siz[rs[x]]+1;}
inline int isrs(int x){return x==rs[fa[x]];}
inline bool isroot(int x){
if(!fa[x]) return 1;
return ls[fa[x]]!=x && rs[fa[x]]!=x;
}
inline void pushdown(int x){
if(rev[x]){
swap(ls[x],rs[x]);
if(ls[x]) rev[ls[x]]^=1;
if(rs[x]) rev[rs[x]]^=1;
rev[x]=0;
}
}
inline void rotate(int x){
int y=fa[x],z=fa[y],b=(ls[y]==x?rs[x]:ls[x]);
if(z && !isroot(y)) (ls[z]==y?ls[z]:rs[z])=x;
fa[x]=z;fa[y]=x;b?fa[b]=y:0;
if(ls[y]==x) rs[x]=y,ls[y]=b;
else ls[x]=y,rs[y]=b;
pushup(y);pushup(x);
}
int que[N];
inline void splay(int x){
que[que[0]=1]=x;
for(int y=x;!isroot(y);y=fa[y]) que[++que[0]]=fa[y];
for(int i=que[0];i;i--) pushdown(que[i]);
while(!isroot(x)){
if(!isroot(fa[x])){
if(isrs(fa[x])==isrs(x)) rotate(fa[x]);
else rotate(x);
}
rotate(x);
}
pushup(x);
}
inline void access(int x){for(int y=0;x;y=x,x=fa[x]){splay(x);rs[x]=y;if(y) fa[y]=x;pushup(x);}}
inline void makeroot(int x){access(x);splay(x);rev[x]^=1;}
inline void link(int x,int y){makeroot(x);fa[x]=y;}
inline void cut(int x,int y){makeroot(x);access(y);splay(y);ls[y]=fa[x]=0;pushup(y);}
inline int add(int x){
a[++tot]=x;x=tot;
set<int,cmp>::iterator it=s.insert(tot).first;
if(!root) pushup(root=x);
else{
int f1=0,f2=0,d1=0,d2=0;
if(it!=s.begin()) f1=*(--it),makeroot(root),access(f1),splay(f1),d1=siz[f1],++it;
++it;
if(it!=s.end()) f2=*it,makeroot(root),access(f2),splay(f2),d2=siz[f2];
--it;
if(d1>d2) R[f1]=x,F[x]=f1,pushup(x),link(f1,x);
else L[f2]=x,F[x]=f2,pushup(x),link(f2,x);
}
makeroot(root);access(x);splay(x);
return siz[x];
}
inline int getmn(int kd){
int x=*s.begin(),y;
int res;
if(kd) s.erase(x);
makeroot(root);access(x);splay(x);res=siz[x],y=R[x];
if(x==root){if(kd && y) F[y]=0,cut(x,y),root=y;}
else{
cut(x,F[x]),L[F[y]]=y,pushup(x);
if(y) cut(x,y),F[y]=F[x],L[F[y]]=y,link(y,F[x]);
F[x]=0;
if(!kd){
splay(root),F[root]=x,R[x]=root,pushup(root);
link(x,root);root=x;
}
}
return res;
}
inline int getmx(int kd){
int x=*s.rbegin(),y;
int res;
if(kd) s.erase(x);
makeroot(root);access(x);splay(x);res=siz[x],y=L[x];
if(x==root){if(kd && y) F[y]=0,cut(x,y),root=y;}
else{
cut(x,F[x]),R[F[y]]=y,pushup(x);
if(y) cut(x,y),F[y]=F[x],R[F[y]]=y,link(y,F[x]);
F[x]=0;
if(!kd){
splay(root),F[root]=x,L[x]=root,pushup(root);
link(x,root);root=x;
}
}
return res;
}
}
int main(){
int q=read();
while(q--){
int op=read();
if(op==1) cout<<LCT::add(read())<<"\n";
if(op==2) cout<<LCT::getmn(0)<<"\n";
if(op==3) cout<<LCT::getmx(0)<<"\n";
if(op==4) cout<<LCT::getmn(1)<<"\n";
if(op==5) cout<<LCT::getmx(1)<<"\n";
}
return 0;
}
本文详细解析了BZOJ4825题目的解决方案,利用LCT算法进行点的大小关系维护,通过旋转操作更新父子节点关系,实现高效的数据结构操作。代码示例展示了如何使用LCT算法进行点的插入、获取最小和最大值等操作。

157

被折叠的 条评论
为什么被折叠?



