「BZOJ3123」[SDOI2013]森林

用主席树记录每个节点到根节点的信息,用树上差分的思想查询。

合并时把节点数小的合并到节点数大的上,也就是启发式合并,

合并时重建小树上的主席树。

  1 #include<cstdio>
  2 #include<vector>
  3 #include<algorithm>
  4 using namespace std;
  5 const int N=80010,M=N*128,P=20;
  6 int n,m,q,maxp,a[N],rank[N],pos[N];
  7 int fa[N][P],dep[N],siz[N];
  8 int root[N],treeroot[N];
  9 int tot,lc[M],rc[M],sum[M];
 10 vector<int>g[N];
 11 int cmp(const int x,const int y){return a[x]<a[y];}
 12 inline int read(){
 13     int x=0,w=1;char c=0;
 14     while(c<'0'||c>'9'){if(c=='-') w=-1;c=getchar();}
 15     while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();
 16     return x*w;
 17 }
 18 void insert(int& k,int l,int r,int v){
 19     tot++;
 20     lc[tot]=lc[k],rc[tot]=rc[k],sum[tot]=sum[k]+1;
 21     k=tot;
 22     if(l==r) return;
 23     int mid=(l+r)>>1;
 24     if(v<=mid) insert(lc[k],l,mid,v);
 25     else insert(rc[k],mid+1,r,v);
 26     return;
 27 }
 28 int que(int now1,int now2,int pre1,int pre2,int l,int r,int k){
 29     if(l==r) return l;
 30     int mid=(l+r)>>1;
 31     int lsum=sum[lc[now1]]+sum[lc[now2]]-sum[lc[pre1]]-sum[lc[pre2]];
 32     if(lsum>=k) return que(lc[now1],lc[now2],lc[pre1],lc[pre2],l,mid,k);
 33     else return que(rc[now1],rc[now2],rc[pre1],rc[pre2],mid+1,r,k-lsum);
 34 }
 35 void dfs(int k,int father,int d,int r){ //dfs同时建立主席树
 36     treeroot[k]=r,fa[k][0]=father,dep[k]=d,siz[k]=1;
 37     int x;
 38     for(int i=1;i<=17;i++) fa[k][i]=fa[fa[k][i-1]][i-1];
 39     for(int i=0;i<g[k].size();i++){
 40         x=g[k][i];
 41         if(x==father) continue;
 42         root[x]=root[k];
 43         insert(root[x],1,n,rank[x]);
 44         dfs(x,k,d+1,r);
 45         siz[k]+=siz[x];
 46     }
 47     return;
 48 }
 49 int getlca(int x,int y){
 50     if(dep[x]<dep[y]) swap(x,y);
 51     for(int i=17;i>=0;i--)
 52         if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
 53     if(x==y) return x;
 54     for(int i=17;i>=0;i--)
 55         if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
 56     return fa[x][0];
 57 }
 58 void marge(int s,int t){
 59     if(siz[treeroot[s]]<siz[treeroot[t]]) swap(s,t);
 60     root[t]=root[s];
 61     insert(root[t],1,n,rank[t]);
 62     dfs(t,s,dep[s]+1,treeroot[s]);
 63     return;
 64 }
 65 void reset(){
 66     tot=0;
 67     for(int i=1;i<=n;i++) g[i].clear();
 68     return;
 69 }
 70 void solve(){
 71     char opt[10];
 72     int t1,t2,t3;
 73     n=read(),m=read(),q=read();
 74     for(int i=1;i<=n;i++) a[i]=read(),pos[i]=i;
 75     sort(pos+1,pos+n+1,cmp);
 76     for(int i=1;i<=n;i++) rank[pos[i]]=i;
 77     for(int i=1;i<=m;i++){t1=read(),t2=read();g[t1].push_back(t2);g[t2].push_back(t1);}
 78     for(int i=1;i<=n;i++) if(!dep[i]){
 79         root[i]=0;
 80         insert(root[i],1,n,rank[i]);
 81         dfs(i,0,1,i);
 82     }
 83     int lastans=0;
 84     while(q--){
 85         scanf("%s",opt);
 86         t1=read(),t2=read();
 87         if(opt[0]=='Q'){
 88             t3=read();
 89             t1^=lastans,t2^=lastans,t3^=lastans;
 90             int lca=getlca(t1,t2);
 91             lastans=a[pos[que(root[t1],root[t2],root[lca],root[fa[lca][0]],1,n,t3)]];
 92             printf("%d\n",lastans);
 93         }else{
 94             t1^=lastans,t2^=lastans;
 95             g[t1].push_back(t2);g[t2].push_back(t1);
 96             marge(t1,t2);
 97         }
 98     }
 99     reset();
100     return;
101 }
102 int main(){
103     int T;
104     while(scanf("%d",&T)!=EOF) solve();
105     return 0;
106 }

 

posted @ 2018-03-13 10:46  Cupcake  阅读(125)  评论(0编辑  收藏  举报