文章目录
- 前言
- 数据结构模板
- 并查集
- 带权并查集
- 堆
- hash表
- RMQ
- 线段树
- 树状数组
- 树状数组区间修改版
- 分块
- 主席树
- 有旋Treap
- Splay
- 替罪羊树
- 文艺平衡树-Splay
- 点分治
- 树链剖分
- 可持久化并查集
- LCT
- 左偏树
前言
因为老是懒得打模板的时候老是扣不到自己的标(因为之前的都打得太丑了),所以导致我十分的不爽。便打算开一个模板库。会不断更新的
数据结构模板
并查集
int find(int x)//并查集
{return f[x]==x?x:(f[x]=find(f[x]));}
void unionn(int x,int y)//连接
{int fa=find(x),fb=find(y);if(fa<fb) f[fa]=fb;else f[fb]=fa;
}
带权并查集
int find(int x)
{if (father[x]==x) {return x;}else{int fa=father[x];father[x]=find(father[x]);far[x]=far[x]+far[fa]0;return father[x];}
}
void unionn(int x,int y,int w)
{int fa=find(x),fb=find(y);father[fb]=fa;far[fb]=far[x]-far[y]+w;
}
堆
#include<cstdio>
#include<algorithm>
using namespace std;
int a[1000010],num,x,n,v;
void up(int x)
{int t;while (x>1 && a[x]<a[x/2]){t=a[x];a[x]=a[x/2];a[x/2]=t;x/=2;}
}
void down(int x)
{int t,y;while (x*2<=num && a[x]>a[x*2] || x*2+1<=num && a[x]>a[x*2+1]){y=x*2;if (x*2+1<=num && a[x*2]>a[x*2+1]) y++;t=a[x];a[x]=a[y];a[y]=t;x=y;}
}
void insert(int x)
{a[++num]=x;up(num);}
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&v);if(v==1){scanf("%d",&x);a[++num]=x;up(num);}else if(v==2){printf("%d\n",a[1]);}else{swap(a[1],a[num]);num--;down(1);}}
}
hash表
int n,s,hash[maxn+10],a[5001];
bool v[maxn+10];
int hashmath(int x)
{return (x%maxn+maxn)%maxn;}
int locate(int x)//查找位置
{int i=0,w=hashmath(x);while (i<maxn&&v[(w+i)%maxn]&&hash[(w+i)%maxn]!=x)i++;return (w+i)%maxn;
}
void ins(int x)//插入
{int w=locate(x);hash[w]=x;v[w]=true;
}
bool find(int x)//查找
{int w=locate(x);if (hash[w]==x&&v[w]) return true;else return false;
}
RMQ
#include<cstdio>
#include<cmath>
//开log用
#include<iostream>
using namespace std;
int f[100001][21],n,m,z,x,y;
int main()
{scanf("%d%d",&n,&m);for (int i=1;i<=n;i++)scanf("%d",&f[i][0]);//输出for (int j=1;(1<<j)<=n;j++)for (int i=1;i+(1<<j)-1<=n;i++){f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);//动态转移}for (int i=1;i<=m;i++){scanf("%d%d",&x,&y);z=(int)(log(y-x+1)/log(2));//计算xprintf("%d\n",max(f[x][z],f[y+1-(1<<z)][z]));//输出}
}
线段树
#include<cstdio>
#include<algorithm>
#define N 100010
#define ll long long
using namespace std;
struct treenode{int l,r;ll val,lazy;
}t[N*4];
int n,m,l,r;
ll x;
char c[2];
void build(int x,int l,int r)//建树
{t[x].l=l;t[x].r=r;if(l==r){scanf("%lld",&t[x].val);return;}int mid=(l+r)>>1;build(x*2,l,mid);build(x*2+1,mid+1,r);t[x].val=t[x*2].val+t[x*2+1].val;
}
void downdata(int x)//下传标记
{if(t[x].lazy){t[x*2].lazy+=t[x].lazy;t[x*2].val+=t[x].lazy*(t[x*2].r-t[x*2].l+1);t[x*2+1].lazy+=t[x].lazy;t[x*2+1].val+=t[x].lazy*(t[x*2+1].r-t[x*2+1].l+1);t[x].lazy=0;}
}
void change(int x,int l,int r,ll num)//区间修改
{if(t[x].l==l&&t[x].r==r){t[x].val+=num*(t[x].r-t[x].l+1);t[x].lazy+=num;return;}downdata(x);int mid=(t[x].l+t[x].r)>>1;if(r<=mid) change(x*2,l,r,num);else if(l>mid) change(x*2+1,l,r,num);else change(x*2,l,mid,num),change(x*2+1,mid+1,r,num);t[x].val=t[x*2].val+t[x*2+1].val;
}
ll find(int x,int l,int r)//区间查询
{if(t[x].l==l&&t[x].r==r)return t[x].val;downdata(x);int mid=(t[x].l+t[x].r)>>1;if(r<=mid) return find(x*2,l,r);else if(l>mid) return find(x*2+1,l,r);else return find(x*2,l,mid)+find(x*2+1,mid+1,r);
}
int main()
{scanf("%d%d",&n,&m);build(1,1,n);for(int i=1;i<=m;i++){scanf("%s %d %d",c,&l,&r);if(c[0]=='Q') printf("%lld\n",find(1,l,r));else{scanf("%lld",&x);change(1,l,r,x);}}
}
树状数组
int lowbit(int x)
{return x&(x^(x-1));}
void change(int x,int num)//修改
{int i=x;while(i<=82000){c[i]+=num;i+=lowbit(i);}
}
int getsum(int x)//求值
{int sum=0;while (x>0){sum+=c[x];x-=lowbit(x);}return sum;
}
树状数组区间修改版
#include<cstdio>
#include<algorithm>
#include<iostream>
#define lobit(x) x&-x
using namespace std;
long long t[2][100010],x,a[100010],sum[100010];
int n,m,l,r;
void add(int k,int x,int num)//修改
{while(x<=n){t[k][x]+=num;x+=lobit(x);}
}
long long ask(int k,int x)//查询
{long long sum=0;while(x>0){sum+=t[k][x];x-=lobit(x);}return sum;
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%lld",&a[i]);sum[i]=sum[i-1]+a[i];}for(int i=1;i<=m;i++){char c[2];scanf("%s %d %d",c,&l,&r);if(c[0]=='Q'){long long ans=sum[r]+(r+1)*ask(0,r)-ask(1,r);ans-=sum[l-1]+l*ask(0,l-1)-ask(1,l-1);//查询printf("%lld\n",ans);}else{scanf("%d",&x);add(0,l,x);add(0,r+1,-x);add(1,l,l*x);add(1,r+1,-(r+1)*x);//修改}}
}
分块
#include<cstdio>
#include<algorithm>
#include<cmath>
#define ll long long
#define N 100010
using namespace std;
ll a[N],sum[N],add[N];
int L[N],R[N],d;
int pos[N];
int n,m,t,l,r;
char op[3];
void change(int l,int r,long long d)
{int p=pos[l],q=pos[r];if(p==q){for(int i=l;i<=r;i++) a[i]+=d;sum[p]+=d*(r-l+1);}//全都在一块中else{for(int i=p+1;i<=q-1;i++) add[i]+=d;//维护中间段落for(int i=l;i<=R[p];i++) a[i]+=d;sum[p]+=d*(R[p]-l+1);for(int i=L[q];i<=r;i++) a[i]+=d;sum[q]+=d*(r-L[q]+1);//暴力局部修改}
}
ll ask(int l,int r)
{int p=pos[l],q=pos[r];ll ans=0;if(p==q){for(int i=l;i<=r;i++) ans+=a[i];ans+=add[p]*(r-l+1);}//全部都在一块中else{for(int i=p+1;i<=q-1;i++)ans+=sum[i]+add[i]*(R[i]-L[i]+1);//累加中间段落for(int i=l;i<=R[p];i++) ans+=a[i];ans+=add[p]*(R[p]-l+1);for(int i=L[q];i<=r;i++) ans+=a[i];ans+=add[q]*(r-L[q]+1);//暴力局部累加}return ans;
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%lld",&a[i]);t=sqrt(n);for(int i=1;i<=t;i++){L[i]=(i-1)*t+1;R[i]=i*t;}//标记每块左右if(R[t]<n) t++,L[t]=R[t-1]+1,R[t]=n;//补足尾部for(int i=1;i<=t;i++)for(int j=L[i];j<=R[i];j++){pos[j]=i;//表示属于哪个块sum[i]+=a[j];//计算段落和}for(int i=1;i<=m;i++){scanf("%s %d %d",op,&l,&r);if(op[0]=='C'){scanf("%d",&d);change(l,r,d);}else printf("%lld\n",ask(l,r));}
}
主席树
#include<cstdio>
#include<algorithm>
#define MN 200010
using namespace std;
struct tnode{int w,l,r,ls,rs;
}t[MN<<5];
int n,m,x,y,k,a[MN],b[MN],root[MN],num,q,w;
int build(int l,int r)//建立一棵空树
{int k=++num;t[k].l=l,t[k].r=r;if (l==r) return k;int mid=(l+r)>>1;t[k].ls=build(l,mid);t[k].rs=build(mid+1,r);//左右分区return k;//返回编号
}
int addt(int k,int z)//建立一条新链
{int nb=++num;t[nb]=t[k];t[nb].w++;//动态开点if (t[k].l==z&&t[k].r==z) return nb;//到达节点int mid=(t[k].l+t[k].r)>>1;if (z<=mid) t[nb].ls=addt(t[k].ls,z);else t[nb].rs=addt(t[k].rs,z);//建立下一个节点return nb;
}
int query(int k1,int k2,int k)//前缀和询问区间
{if (t[k1].l==t[k1].r) return t[k1].l;w=t[t[k2].ls].w-t[t[k1].ls].w;//计算左子树在这个区间内的数字数量if (k<=w) return query(t[k1].ls,t[k2].ls,k);else return query(t[k1].rs,t[k2].rs,k-w);//向下询问
}
int main()
{scanf("%d%d",&n,&m);for (int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];sort(b+1,b+1+n);//排序(离散化1)int q=unique(b+1,b+1+n)-b-1;//去重(离散化)root[0]=build(1,q);//建立空树for (int i=1;i<=n;i++){int te=lower_bound(b+1,b+1+q,a[i])-b;//二分寻找原来的位置root[i]=addt(root[i-1],te);//建立一条链}for (int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&k);printf("%d\n",b[query(root[x-1],root[y],k)]);//询问区间}
}
有旋Treap
#include<cstdio>
#include<algorithm>
#define INF 2147483647/3
#define N 100010
using namespace std;
int n,root;
struct Treap_node{int l[N],r[N];int val[N],dat[N];int cnt[N],size[N];int tot;int New(int new_val){val[++tot]=new_val;dat[tot]=rand();cnt[tot]=size[tot]=1;return tot;}void Updata(int p){size[p]=size[l[p]]+size[r[p]]+cnt[p];}void Build(){New(-INF);New(INF);root=1;r[1]=2;Updata(root);}int GetRankByVal(int p,int num){if(p==0) return 0;if(num==val[p]) return size[l[p]]+1;if(num<val[p]) return GetRankByVal(l[p],num);return GetRankByVal(r[p],num)+size[l[p]]+cnt[p];}int GetValByRank(int p,int rank){if (p==0) return INF;if(size[l[p]]>=rank) return GetValByRank(l[p],rank);if(size[l[p]]+cnt[p]>=rank) return val[p];return GetValByRank(r[p],rank-size[l[p]]-cnt[p]);}void zig(int &p){int q=l[p];l[p]=r[q];r[q]=p;p=q;Updata(r[p]);Updata(p);}void zag(int &p){int q=r[p];r[p]=l[q];l[q]=p;p=q;Updata(l[p]);Updata(p);}void Insert(int &p,int num){if(p==0){p=New(num);return;}if(num==val[p]){cnt[p]++;Updata(p);return;}if(num<val[p]){Insert(l[p],num);if(dat[p]<dat[l[p]]) zig(p);}else{Insert(r[p],num);if(dat[p]<dat[r[p]]) zag(p);}Updata(p);}int GetPre(int num){int ans=1;int p=root;while(p){if(num==val[p]){if(l[p]>0){p=l[p];while(r[p]>0) p=r[p];ans=p;}break;}if(val[p]<num&&val[p]>val[ans]) ans=p;p=num<val[p]?l[p]:r[p];}return val[ans];}int GetNext(int num){int ans=2;int p=root;while(p){if(num==val[p]){if(r[p]>0){p=r[p];while(l[p]>0) p=l[p];ans=p;}break;}if(val[p]>num&&val[p]<val[ans]) ans=p;p=num<val[p]?l[p]:r[p];}return val[ans];}void Remove(int &p,int num){if(p==0) return;if(num==val[p]){if(cnt[p]>1){cnt[p]--;Updata(p);return;}if(l[p]||r[p]){if(r[p]==0||dat[l[p]]>dat[r[p]])zig(p),Remove(r[p],num);elsezag(p),Remove(l[p],num);Updata(p);}else p=0;return;}num<val[p]?Remove(l[p],num):Remove(r[p],num);Updata(p);}
}a;
int main()
{a.Build();scanf("%d",&n);while(n--){int opt,x;scanf("%d%d",&opt,&x);switch(opt){case 1:a.Insert(root,x);break;case 2:a.Remove(root,x);break;case 3:printf("%d\n",a.GetRankByVal(root,x)-1);break;case 4:printf("%d\n",a.GetValByRank(root,x+1));break;case 5:printf("%d\n",a.GetPre(x));break;case 6:printf("%d\n",a.GetNext(x));break;}}
}
Splay
#include<cstdio>
#include<algorithm>
#define INF 2100000000
#define N 100010
using namespace std;
struct splay{int v[N],father[N];int l[N],r[N];int sum[N],recy[N];int n,points;#define root r[0]void Updata(int x){sum[x]=sum[l[x]]+sum[r[x]]+recy[x];}int Identify(int x){return l[father[x]]==x?0:1;}void Connect(int x,int f,int son){father[x]=f;if(son) r[f]=x;else l[f]=x;}void Rotate(int x){int y=father[x];int mroot=father[y];int mrootson=Identify(y);int yson=Identify(x);int B=(yson?l[x]:r[x]);Connect(B,y,yson);Connect(y,x,(yson^1));Connect(x,mroot,mrootson);Updata(y);Updata(x);}void Splay(int at,int to){to=father[to];while(father[at]!=to){int up=father[at];if(father[up]==to) Rotate(at);else if(Identify(up)==Identify(at)){Rotate(up);Rotate(at);}else{Rotate(at);Rotate(at);}}}int CrePoint(int vs,int fathers){n++;v[n]=vs;father[n]=fathers;sum[n]=recy[n]=1;return n;}void Destory(int x){v[x]=l[x]=r[x]=sum[x]=father[x]=recy[x]=0;if(x==n)n--;}int getroot(){return root;}int FindVal(int vs){int now=root;if(!now) return 0;while(true){if(v[now]==vs){Splay(now,root);return root;}int next=vs<v[now]?0:1;if(!(next?r[now]:l[now])) return 0;now=(next?r[now]:l[now]);}}int Build(int vs){points++;if(!n){root=1;CrePoint(vs,0);}else{int now=root;while(1){sum[now]++;if(vs==v[now]){recy[now]++;return now;}int next=vs<v[now]?0:1;if(!(next?r[now]:l[now])){CrePoint(vs,now);if(next) r[now]=n;else l[now]=n;return n;}now=next?r[now]:l[now];}}return 0;}void Insert(int vs){int add=Build(vs);Splay(add,root);}void Remove(int vs){int deal=FindVal(vs);if(!deal) return;points--;if(recy[deal]>1){recy[deal]--;sum[deal]--;return;}if(!l[deal]){root=r[deal];father[root]=0;}else{int lef=l[deal];while(r[lef]) lef=r[lef];Splay(lef,l[deal]);int rig=r[deal];Connect(rig,lef,1);Connect(lef,0,1);Updata(lef);}Destory(deal);}int GetRankByVal(int vs){int now=root;if(!now) return 0;while((vs>v[now]?r[now]:l[now])&&vs!=v[now])now=(vs>v[now]?r[now]:l[now]);Splay(now,root);return sum[l[root]];}int GetValByRank(int x){if(x>points) return -INF;int now=root;while(1){int minused=sum[now]-sum[r[now]];if(x>sum[l[now]]&&x<=minused) break;if(x<minused)now=l[now];else{x-=minused;now=r[now];}}Splay(now,root);return v[now];}int Upper(int vs){int now=root;int result=INF;while(now){if(v[now]>vs&&v[now]<result) result=v[now];if(vs<v[now]) now=l[now];else now=r[now];}return result;}int Lower(int vs){int now=root;int result=-INF;while(now){if(v[now]<vs&&v[now]>result) result=v[now];if(vs>v[now]) now=r[now];else now=l[now];}return result;}#undef root
}a;
int main(){freopen("testdata.in","r",stdin);freopen("data.out","w",stdout);a.Insert(-INF);a.Insert(INF);int m;scanf("%d",&m);while(m--){int opt,x;scanf("%d%d",&opt,&x);if(opt==1) a.Insert(x);if(opt==2) a.Remove(x);if(opt==3) printf("%d\n",a.GetRankByVal(x));if(opt==4) printf("%d\n",a.GetValByRank(x+1));if(opt==5) printf("%d\n",a.Lower(x));if(opt==6) printf("%d\n",a.Upper(x));}
}
替罪羊树
#include<cstdio>
#include<algorithm>
#include<cctype>
#define alpha 0.8
#define N 100010
using namespace std;
inline int read(){int x(0),sign(0);char ch=getchar();while(!isdigit(ch)){if(ch=='-') sign=1;ch=getchar();}while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();return sign?-x:x;
}
struct goat_Tree{int l[N],r[N],size[N],val[N],valid[N],total[N];int cur[N],memory[N];bool exist[N];int root,poi,pool,cnt;void ReMemory(){for(int i=N-10;i>=1;i--)memory[++pool]=i;}bool Isbad(int now){if((double)valid[now]*alpha<=(double)max(valid[l[now]],valid[r[now]]))return true;else return false;}void Beat(int now){if(!now) return;Beat(l[now]);if(exist[now]) cur[++poi]=now;else memory[++pool]=now;Beat(r[now]);}void New(int x){l[x]=r[x]=0;total[x]=valid[x]=1;}void Build(int ls,int rs,int &now){int mid=(ls+rs)>>1;now=cur[mid];if(ls==rs){New(now);return;}if(ls<mid) Build(ls,mid-1,l[now]);else l[now]=0;Build(mid+1,rs,r[now]);total[now]=total[l[now]]+total[r[now]]+1;valid[now]=valid[l[now]]+valid[r[now]]+1;}void ReBuild(int &now){poi=0;Beat(now);if(poi) Build(1,poi,now);else now=0;}int GetRankByVal(int k){int now=root;int ans=1;while(now){if(val[now]>=k) now=l[now];else{ans+=valid[l[now]]+exist[now];now=r[now];}}return ans;}int GetValByRank(int k){int now=root;while(now){if(exist[now]&&valid[l[now]]+1==k)return val[now];if(valid[l[now]]>=k) now=l[now];else{k-=valid[l[now]]+exist[now];now=r[now];}}}void Insert(int &now,int num){if(!now){now=memory[pool--];val[now]=num;New(now);exist[now]=1;return;}total[now]++;valid[now]++;if(val[now]>=num) Insert(l[now],num);else Insert(r[now],num);if(Isbad(now))ReBuild(now);}void Remove_z(int &now,int tar){if(exist[now]&&valid[l[now]]+1==tar){exist[now]=0;valid[now]--;return;}valid[now]--;if(valid[l[now]]+exist[now]>=tar)Remove_z(l[now],tar);else Remove_z(r[now],tar-valid[l[now]]-exist[now]);}void Remove(int tar){Remove_z(root,GetRankByVal(tar));if((double)total[root]*alpha>valid[root])ReBuild(root);}
}a;
int main()
{int opt,x,m;a.ReMemory();scanf("%d",&m);while(m--){opt=read();x=read();if(opt==1) a.Insert(a.root,x);if(opt==2) a.Remove(x);if(opt==3) printf("%d\n",a.GetRankByVal(x));if(opt==4) printf("%d\n",a.GetValByRank(x));if(opt==5) printf("%d\n",a.GetValByRank(a.GetRankByVal(x)-1));if(opt==6) printf("%d\n",a.GetValByRank(a.GetRankByVal(x+1)));}
}
文艺平衡树-Splay
#include<cstdio>
#include<algorithm>
#define INF 2100000000
#define N 100010
using namespace std;
struct splay{int v[N],father[N],root;int l[N],r[N];int sum[N],mark[N];int n,points;void Updata(int x){sum[x]=sum[l[x]]+sum[r[x]]+1;}void Downdata(int x){if(mark[x]){mark[l[x]]^=1;mark[r[x]]^=1;mark[x]=0;swap(l[x],r[x]);}}void New(int x,int vs,int fa){l[x]=r[x]=0;sum[x]=1;v[x]=vs;father[x]=fa;}void Rotate(int x){int y=father[x];int z=father[y];int k=r[y]==x;if(r[z]==y) r[z]=x;else l[z]=x;father[x]=z;if(k) r[y]=l[x];else l[y]=r[x];father[k?l[x]:r[x]]=y;if(k) l[x]=y;else r[x]=y;father[y]=x;Updata(y);Updata(x);}void Splay(int at,int to){while(father[at]!=to){int y=father[at];int z=father[y];if(z!=to)(r[z]==y)^(r[z]==at)?Rotate(at):Rotate(y);Rotate(at);}if(to==0)root=at;}void Insert(int x){int now=root,ff=0;while(now)ff=now,now=(x>v[now]?r[now]:l[now]);now=++n;if(ff&&x>v[now]) r[ff]=now;else if(ff) l[ff]=now;New(now,x,ff);Splay(now,0);}int GetValByRank(int k){int now=root;while(1){Downdata(now);if(sum[l[now]]>=k) now=l[now];else if(sum[l[now]]+1==k) return now;else k-=sum[l[now]]+1,now=r[now];}}void Work(int ls,int rs){ls=GetValByRank(ls);rs=GetValByRank(rs+2);Splay(ls,0);Splay(rs,ls);mark[l[r[root]]]^=1;}void Write(int x,int mn){Downdata(x);if(l[x]) Write(l[x],mn);if(v[x]>1&&v[x]<mn+2) printf("%d ",v[x]-1);if(r[x]) Write(r[x],mn);}
}a;
int main(){//freopen("testdata.in","r",stdin);//freopen("data.out","w",stdout);int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n+2;i++)a.Insert(i);while(m--){int l,r;scanf("%d%d",&l,&r);a.Work(l,r);}a.Write(a.root,n);
}
点分治
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 100010
#define inf 10000000
using namespace std;
struct node{int to,next,w;
}a[N*2];
int n,m,que[1010],ok[inf],tot,sum,num,q[N];
int root,siz[N],f[N],ls[N],st[N],dis[N];
int lon[inf];
bool v[N];
void addl(int x,int y,int w)
{a[++tot].to=y;a[tot].next=ls[x];a[tot].w=w;ls[x]=tot;
}
void groot(int x,int fa)
{siz[x]=1;f[x]=0;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa||v[y]) continue;groot(y,x);siz[x]+=siz[y];f[x]=max(f[x],siz[y]);}f[x]=max(f[x],sum-siz[x]);if(f[x]<f[root]) root=x;
}
void get_dis(int x,int fa)
{st[++num]=dis[x];for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa||v[y]) continue;dis[y]=dis[x]+a[i].w;get_dis(y,x);}
}
void calc(int x)
{int p=0;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(v[y]) continue;num=0;dis[y]=a[i].w;get_dis(y,x);for(int j=num;j;j--)for(int k=1;k<=m;k++)ok[k]|=lon[que[k]-st[j]];for(int j=num;j;j--)q[++p]=st[j],lon[st[j]]=1;}for(int i=1;i<=p;i++)lon[q[i]]=0;
}
void solve(int x)
{v[x]=lon[0]=1;calc(x);for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(v[y]) continue;sum=siz[y];f[root=0]=n;groot(y,0);solve(y);}
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<n;i++){int x,y,w;scanf("%d%d%d",&x,&y,&w);addl(x,y,w);addl(y,x,w);}for(int i=1;i<=m;i++)scanf("%d",&que[i]);f[0]=n;sum=n;groot(1,0);solve(root);for(int i=1;i<=m;i++)if(ok[i]) printf("AYE\n");else printf("NAY\n");
}
树链剖分
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=200000;
int tot,cnt,n,m,s,p,ls[N],pw[N],id[N];
int siz[N],dep[N],f[N],son[N],seg[N],top[N];
struct treenode{int l,r,lazy,val;
};
struct LineTree{treenode t[N*2];void build(int x,int l,int r){t[x].l=l;t[x].r=r;if(l==r){t[x].val=pw[id[l]]%p;return;}int mid=(l+r)>>1;build(x*2,l,mid);build(x*2+1,mid+1,r);t[x].val=(t[x*2].val+t[x*2+1].val)%p;}void downdata(int x){if(t[x].lazy){(t[x*2].lazy+=t[x].lazy)%=p;(t[x*2].val+=t[x].lazy*(t[x*2].r-t[x*2].l+1))%=p;(t[x*2+1].lazy+=t[x].lazy)%=p;(t[x*2+1].val+=t[x].lazy*(t[x*2+1].r-t[x*2+1].l+1))%=p;t[x].lazy=0;}}void change(int x,int l,int r,int num){if(t[x].l==l&&t[x].r==r){(t[x].val+=num*(t[x].r-t[x].l+1))%=p;(t[x].lazy+=num)%=p;return;}downdata(x);int mid=(t[x].l+t[x].r)>>1;if(r<=mid) change(x*2,l,r,num);else if(l>mid) change(x*2+1,l,r,num);else change(x*2,l,mid,num),change(x*2+1,mid+1,r,num);t[x].val=(t[x*2].val+t[x*2+1].val)%p;}int find(int x,int l,int r){if(t[x].l==l&&t[x].r==r)return t[x].val;downdata(x);int mid=(t[x].l+t[x].r)>>1;if(r<=mid) return find(x*2,l,r);else if(l>mid) return find(x*2+1,l,r);else return (find(x*2,l,mid)+find(x*2+1,mid+1,r))%p; }
}LT;
struct edge_node{int to,next;
}a[N*2];
void addl(int x,int y)
{a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;
}
void dfs1(int x,int fa)
{siz[x]=1;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa) continue;dep[y]=dep[x]+1;f[y]=x;dfs1(y,x);siz[x]+=siz[y];if(siz[y]>siz[son[x]])son[x]=y;}
}
void dfs2(int x,int fa)
{seg[x]=++cnt;id[cnt]=x;if(son[x]){top[son[x]]=top[x];dfs2(son[x],x);}for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa||y==son[x]) continue;top[y]=y;dfs2(y,x);}
}
void path_change(int x,int y,int z)
{while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]]) swap(x,y);LT.change(1,seg[top[x]],seg[x],z);x=f[top[x]];}if(dep[x]>dep[y]) swap(x,y);LT.change(1,seg[x],seg[y],z);return;
}
int path_ask(int x,int y)
{int ans=0;while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]]) swap(x,y);(ans+=LT.find(1,seg[top[x]],seg[x]))%=p;x=f[top[x]];}if(dep[x]>dep[y]) swap(x,y);(ans+=LT.find(1,seg[x],seg[y]))%=p;return ans;
}
int main()
{scanf("%d%d%d%d",&n,&m,&s,&p);for(int i=1;i<=n;i++)scanf("%d",&pw[i]);for(int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);addl(x,y);addl(y,x);}dfs1(s,0);top[s]=s;dfs2(s,0);LT.build(1,1,n);for(int i=1;i<=m;i++){int t,x,y,z;scanf("%d%d",&t,&x);if(t==1){scanf("%d%d",&y,&z);path_change(x,y,z);}if(t==2){scanf("%d",&y);printf("%d\n",path_ask(x,y));}if(t==3){scanf("%d",&z);LT.change(1,seg[x],seg[x]+siz[x]-1,z);}if(t==4){printf("%d\n",LT.find(1,seg[x],seg[x]+siz[x]-1));}}
}
可持久化并查集
// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+100;
struct Tree_node{int ls,rs,l,r,deep,fa;
};
int n,m,cnt,root[N],edt;
struct Keep_tree{Tree_node t[N*40];void Build(int &x,int l,int r){x=++cnt;t[x].l=l;t[x].r=r;if(l==r){t[x].fa=l;return;}int mid=(t[x].l+t[x].r)/2;Build(t[x].ls,l,mid);Build(t[x].rs,mid+1,r);}Tree_node Query(int x,int pos){if(t[x].l==t[x].r)return t[x];if(pos<=t[t[x].ls].r) return Query(t[x].ls,pos);return Query(t[x].rs,pos);}void Insert(int x,int &y,int pos,int nef){y=++cnt;t[y]=t[x];if(t[x].l==t[x].r){t[y].fa=nef;return;}if(pos<=t[t[x].ls].r) Insert(t[x].ls,t[y].ls,pos,nef);else Insert(t[x].rs,t[y].rs,pos,nef);}void add(int x,int pos){if(t[x].l==t[x].r){t[x].deep++;return;}if(pos<=t[t[x].ls].r) add(t[x].ls,pos);else add(t[x].rs,pos);}
}Tree;
Tree_node find_fa(int ed,int x)
{Tree_node Fa=Tree.Query(root[ed],x);if(x==Fa.fa) return Fa;return find_fa(ed,Fa.fa);
}
void unionn(int x,int y)
{Tree_node Fa=find_fa(edt-1,x),Fb=find_fa(edt-1,y);if(Fa.fa==Fb.fa) return;if(Fa.deep<Fb.deep) swap(Fa,Fb);Tree.Insert(root[edt-1],root[edt],Fb.fa,Fa.fa);if(Fa.deep==Fb.deep)Tree.add(root[edt],Fa.fa);
}
int main()
{scanf("%d%d",&n,&m);Tree.Build(root[0],1,n);for(int i=1;i<=m;i++){int op,x,y;scanf("%d",&op);++edt;root[edt]=root[edt-1];if(op==1){scanf("%d%d",&x,&y);unionn(x,y);}if(op==2){scanf("%d",&x);root[edt]=root[x];}if(op==3){scanf("%d%d",&x,&y);if(find_fa(edt,x).fa==find_fa(edt,y).fa) printf("1");else printf("0");putchar('\n');}}
}
LCT
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3e5+100;
int n,m,v[N];
struct Link_Cut_Tree{int w[N],fa[N],son[N][2];bool r[N];#define ls son[x][0]#define rs son[x][1]bool nroot(int x){return son[fa[x]][0]==x||son[fa[x]][1]==x;}void PushUp(int x){w[x]=w[ls]^w[rs]^v[x];return;}void PushR(int x){swap(ls,rs);r[x]^=1;return;}void PushDown(int x){if(r[x]){if(ls) PushR(ls);if(rs) PushR(rs);r[x]=0;}return;}void Rotate(int x){int y=fa[x],z=fa[y],k=(son[y][1]==x),w=son[x][!k];if(nroot(y)) son[z][son[z][1]==y]=x;son[x][!k]=y;son[y][k]=w;if(w) fa[w]=y;fa[y]=x;fa[x]=z;PushUp(y);return;}void PushHall(int x){if(nroot(x)) PushHall(fa[x]);PushDown(x); return;}void Splay(int x){int y=x,z=0;PushHall(x);while(nroot(x)){y=fa[x];z=fa[y];if(nroot(y))Rotate((son[y][0]==x)^(son[z][0]==y)?x:y);Rotate(x);} PushUp(x);return;}void Access(int x){for(int y=0;x;x=fa[y=x])Splay(x),rs=y,PushUp(x);return;}void MakeRoot(int x){Access(x);Splay(x);PushR(x);return;}int FindRoot(int x){Access(x);Splay(x);while(ls) PushDown(x),x=ls;Splay(x);return x;}void Split(int x,int y){MakeRoot(x);Access(y);Splay(y);return;}void Link(int x,int y){MakeRoot(x);if(FindRoot(y)!=x) fa[x]=y;}void Cut(int x,int y){MakeRoot(x);if(FindRoot(y)==x&&fa[y]==x&&!son[y][0]){fa[y]=son[x][1]=0;PushUp(x);} }#undef ls#undef rs
}LCT;
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",&v[i]);while(m--){int op,x,y;scanf("%d%d%d",&op,&x,&y);if(op==0){LCT.Split(x,y);printf("%d\n",LCT.w[y]);}if(op==1){LCT.Link(x,y);}if(op==2){LCT.Cut(x,y);}if(op==3){LCT.Splay(x);v[x]=y;}}
}
左偏树
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int n,m,val[N];
struct Left_tree{int dis[N],fa[N],t[N][2];int Merge(int x,int y){if(!x||!y) return x+y;if(val[x]>val[y]||(val[x]==val[y]&&x>y))swap(x,y);int &ls=t[x][0],&rs=t[x][1];rs=Merge(rs,y);if(dis[ls]<dis[rs]) swap(ls,rs);fa[rs]=fa[ls]=x;dis[x]=dis[rs]+1;return x;}void Del(int x){int ls=t[x][0],rs=t[x][1];fa[ls]=ls;fa[rs]=rs;val[x]=-1;fa[x]=Merge(ls,rs);}int Get(int x){return (fa[x]==x)?(x):(fa[x]=Get(fa[x]));}
}T;
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",&val[i]),T.fa[i]=i;while(m--){int op,x,y;scanf("%d%d",&op,&x);if(op==1){scanf("%d",&y);if(val[x]==-1||val[y]==-1)continue;x=T.Get(x);y=T.Get(y);T.Merge(x,y);}if(op==2){if(val[x]==-1){printf("-1\n");continue;}x=T.Get(x);printf("%d\n",val[x]);T.Del(x);}}
}