[bzoj 3123][Sdoi2013]森林
这题的技术性不高.
查询的时候按照树上链查询第K大做法做.
连边的时候可以启发式合并,暴力的将一个合并到另一个.
由于是树上的主席树,所以这两个操作维护起来并不是特别困难.
平心而论,对于这道题,出题人是给了我们很多方便的.
还有一个地方是,刚开始输入的T是在比赛时区分数据点数的,没什么用,别看成多组数据.
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<ctime> #include<string> #include<iomanip> #include<algorithm> #include<map> using namespace std; #define LL long long #define FILE "rforest" #define up(i,j,n) for(int i=j;i<=n;++i) #define db double #define ull unsigned long long #define eps 1e-10 #define pii pair<int,int> int read(){ int x=0,f=1,ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f*x; } const int maxn=202000,maxm=20000,mod=(int)(1e9+7+0.1),inf=(int)(1e9); bool cmax(int& a,int b){return a<b?a=b,true:false;} bool cmin(int& a,int b){return a>b?a=b,true:false;} struct node{ int y,next; }e[maxn]; int len=0,linkk[maxn]; void insert(int x,int y){e[++len].y=y;e[len].next=linkk[x];linkk[x]=len;} int fa[maxn][27],dep[maxn],siz[maxn],f[maxn],vis[maxn]; int val[maxn],N,zhu[maxn],v[maxn]; int getfa(int x){return x==f[x]?x:f[x]=getfa(f[x]);} pii t[maxn]; namespace chair_man_tree{ const int maxn=10000000; int c[maxn][2],sum[maxn],cnt=0,root[maxn]; void insert(int pre,int& o,int key,int l,int r){ o=++cnt; if(l==r){ sum[o]=sum[pre]+1; return; } int mid=(l+r)>>1; if(key>mid){ c[o][0]=c[pre][0]; insert(c[pre][1],c[o][1],key,mid+1,r); } else{ c[o][1]=c[pre][1]; insert(c[pre][0],c[o][0],key,l,mid); } sum[o]=sum[c[o][0]]+sum[c[o][1]]; } void build(int x){ insert(root[fa[x][0]],root[x],zhu[x],1,N); } int q[5],w[5]; int query(int K,int l,int r){ int ans=0;up(i,1,4)ans+=w[i]*sum[c[q[i]][0]]; int mid=(l+r)>>1; if(l==r)return r; if(ans<=K){ up(i,1,4)q[i]=c[q[i]][1];K-=ans; return query(K,mid+1,r); } else { up(i,1,4)q[i]=c[q[i]][0]; return query(K,l,mid); } } int Query(int K){ return query(K,1,N); } }; void dfs(int x){ vis[x]=1; chair_man_tree::build(x); for(int i=linkk[x];i;i=e[i].next){ if(e[i].y==fa[x][0])continue; fa[e[i].y][0]=x; f[e[i].y]=x; dep[e[i].y]=dep[x]+1; dfs(e[i].y); } getfa(x); } int getlca(int x,int y){ if(dep[x]>dep[y])swap(x,y); for(int i=25;i>=0;i--)if(dep[y]-dep[x]>=(1<<i))y=fa[y][i]; if(x==y)return x; for(int i=25;i>=0;i--)if(fa[y][i]!=fa[x][i])x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int query(int S,int T,int K){ int lca=getlca(S,T); up(i,1,4)chair_man_tree::w[i]=(i>2?-1:1); chair_man_tree::q[1]=chair_man_tree::root[S]; chair_man_tree::q[2]=chair_man_tree::root[T]; chair_man_tree::q[3]=chair_man_tree::root[lca]; chair_man_tree::q[4]=chair_man_tree::root[fa[lca][0]]; return val[chair_man_tree::Query(K)]; } int q[maxn],tail=0; void Dfs(int x){ chair_man_tree::build(x); q[++tail]=x; for(int i=linkk[x];i;i=e[i].next){ if(e[i].y==fa[x][0])continue; dep[e[i].y]=dep[x]+1; fa[e[i].y][0]=x; f[e[i].y]=fa[e[i].y][0]; Dfs(e[i].y); } getfa(x); } void link(int x,int y){ int f1=getfa(x),f2=getfa(y); if(siz[f1]<siz[f2])swap(x,y),swap(f1,f2); dep[y]=dep[x]+1; insert(x,y);insert(y,x); fa[y][0]=x;f[y]=f1; tail=0; Dfs(y); for(int j=1;j<=25;j++) for(int i=1;i<=tail;i++) fa[q[i]][j]=fa[fa[q[i]][j-1]][j-1]; up(i,1,tail)siz[getfa(q[i])]++; } void print(int* a,int n){ up(i,0,n)if(a[i])printf("%d %d\n",i,a[i]); //cout<<endl; } int main(){ freopen(FILE".in","r",stdin); freopen(FILE".out","w",stdout); int T=read(); int n=read(),m=read(),Q=read(); up(i,1,n)t[i].first=v[i]=read(),t[i].second=i; sort(t+1,t+n+1);t[0].first=-1; up(i,1,n){ if(t[i].first!=t[i-1].first){ val[++N]=t[i].first; } zhu[t[i].second]=N; }//hash up(i,1,m){ int x=read(),y=read(); insert(x,y);insert(y,x); } up(i,1,n)if(!vis[i])f[i]=i,dfs(i); up(i,1,n)siz[getfa(i)]++; for(int j=1;j<=25;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; int last=0;char ch; while(Q--){ scanf(" %c",&ch); int x=read()^last,y=read()^last; if(ch=='Q'){ int K=read()^last; printf("%d\n",last=query(x,y,K-1)); } if(ch=='L') link(x,y); } return 0; }