BZOJ 3123 SDOI2013 森林
首先对于查询操作就是裸的COT QAQ
在树上DFS建出主席树就可以了
对于连接操作,我们发现并没有删除
所以我们可以进行启发式合并,每次将小的树拍扁插入大的树里并重构即可
写完了之后第一个和第二个点迷のRE
然后又重新写了一遍就A了(并不知道为什么,难道第一遍写挫了?
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> using namespace std; const int maxn=100010; int T,n,m,Q,u,v,k,lca,w; int ans=0; char ch; int p[maxn]; int fa[maxn],dep[maxn],sz[maxn]; int anc[maxn][20]; int h[maxn],cnt=0; struct edge{ int to,next; }G[maxn<<1]; void add(int x,int y){++cnt;G[cnt].to=y;G[cnt].next=h[x];h[x]=cnt;} int ufs(int x){return fa[x]==x?x:fa[x]=ufs(fa[x]);} int a[maxn]; struct val{ int v,id; }c[maxn]; bool cmpv(const val &A,const val &B){return A.v<B.v;} bool cmpid(const val &A,const val &B){return A.id<B.id;} int tot=0,rt[maxn]; struct Seg_Tree{ int L,R,v; }t[11000010]; void read(int &num){ num=0;ch=getchar(); while(ch<'!')ch=getchar(); while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); } void build(int &o,int L,int R){ o=++tot; if(L==R)return; int mid=(L+R)>>1; build(t[o].L,L,mid); build(t[o].R,mid+1,R); } void modify(int &o,int now,int L,int R,int p){ t[++tot]=t[now];o=tot; if(L==R){t[o].v++;return;} int mid=(L+R)>>1; if(p<=mid)modify(t[o].L,t[now].L,L,mid,p); else modify(t[o].R,t[now].R,mid+1,R,p); t[o].v=t[t[o].L].v+t[t[o].R].v; } void DFS(int u,int f){ anc[u][0]=f; modify(rt[u],rt[f],1,m,c[u].v); for(int i=1;i<=18;++i){ if(anc[u][i-1]!=0){ int a=anc[u][i-1]; anc[u][i]=anc[a][i-1]; }else anc[u][i]=0; } for(int i=h[u];i;i=G[i].next){ int v=G[i].to; if(v==f)continue; dep[v]=dep[u]+1; DFS(v,u); }return; } int LCA(int p,int q){ if(dep[p]<dep[q])swap(p,q); int d=dep[p]-dep[q]; for(int i=18;i>=0;--i){ if(d>>i&1)p=anc[p][i]; } if(p==q)return p; for(int i=18;i>=0;--i){ if(anc[p][i]!=anc[q][i]&&anc[p][i]!=0)p=anc[p][i],q=anc[q][i]; }return anc[p][0]; } int ask(int u,int v,int lca,int L,int R,int k){ if(L==R)return L; int mid=(L+R)>>1; int now=t[t[u].L].v+t[t[v].L].v-2*t[t[lca].L].v+(w<=mid&&w>=L); if(k>now)return ask(t[u].R,t[v].R,t[lca].R,mid+1,R,k-now); else return ask(t[u].L,t[v].L,t[lca].L,L,mid,k); } int main(){ read(T);read(n);read(m);read(Q); for(int i=1;i<=n;++i)read(c[i].v),c[i].id=i,a[i]=c[i].v; for(int i=1;i<=n;++i)fa[i]=i; for(int i=1;i<=m;++i){ read(u);read(v); add(u,v);add(v,u); int d1=ufs(u),d2=ufs(v); if(d1!=d2)fa[d1]=d2; }m=0; sort(c+1,c+n+1,cmpv);sort(a+1,a+n+1); for(int i=1;i<=n;++i){ if(i==1||a[i]!=a[i-1])c[i].v=++m,p[m]=a[i]; else c[i].v=m; } sort(c+1,c+n+1,cmpid); build(rt[0],1,m); for(int i=1;i<=n;++i){ if(ufs(i)==i)DFS(i,0); sz[ufs(i)]++; } while(Q--){ ch=getchar(); while(ch<'!')ch=getchar(); if(ch=='Q'){ scanf("%d%d%d",&u,&v,&k); u^=ans;v^=ans;k^=ans; lca=LCA(u,v);w=c[lca].v; //cout<<u<<' '<<v<<' '<<k<<endl; ans=p[ask(rt[u],rt[v],rt[lca],1,m,k)]; printf("%d\n",ans); }else{ scanf("%d%d",&u,&v); u^=ans;v^=ans; //cout<<u<<' '<<v<<endl; int d1=ufs(u),d2=ufs(v); //cout<<d1<<' '<<d2<<endl; if(sz[d1]<sz[d2])swap(u,v),swap(d1,d2); sz[d1]+=sz[d2]; if(d1!=d2)fa[d2]=d1;//d2->d1 dep[v]=dep[u]+1; DFS(v,u);add(u,v);add(v,u); } }return 0; }