[bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+启发式合并)

传送门

 

突然发现好像没有那么难……https://blog.csdn.net/stone41123/article/details/78167288

首先有两个操作,一个查询,一个连接

查询的话,直接在树上建主席树

然后难点在于连接

用启发式合并就可以了(想了半天都没想出来)

每次合并时,我们把小的树接到大的上,然后dfs一遍小的树,更新信息

然后注意数组……别太小也别太大……(被数组大小坑了好几次提交)

  1 //minamoto
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  5 char buf[1<<21],*p1=buf,*p2=buf;
  6 inline int read(){
  7     #define num ch-'0'
  8     char ch;bool flag=0;int res;
  9     while(!isdigit(ch=getc()))
 10     (ch=='-')&&(flag=true);
 11     for(res=num;isdigit(ch=getc());res=res*10+num);
 12     (flag)&&(res=-res);
 13     #undef num
 14     return res;
 15 }
 16 char obuf[1<<24],*o=obuf;
 17 void print(int x){
 18     if(x>9) print(x/10);
 19     *o++=x%10+48;
 20 }
 21 const int N=80005,M=N*200;
 22 int ver[N<<2],Next[N<<2],head[N];
 23 int a[N],fa[N],sz[N],b[N];
 24 int n,m,tot,q,size,ans;
 25 void add(int u,int v){
 26     ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
 27     ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
 28 }
 29 int L[M],R[M],sum[M],rt[N],cnt;
 30 void update(int last,int &now,int l,int r,int x){
 31     sum[now=++cnt]=sum[last]+1;
 32     if(l==r) return;
 33     int mid=(l+r)>>1;
 34     if(x<=mid) R[now]=R[last],update(L[last],L[now],l,mid,x);
 35     else L[now]=L[last],update(R[last],R[now],mid+1,r,x);
 36 }
 37 int query(int u,int v,int lca,int lca_fa,int l,int r,int k){
 38     if(l>=r) return l;
 39     int x=sum[L[v]]+sum[L[u]]-sum[L[lca]]-sum[L[lca_fa]];
 40     int mid=(l+r)>>1;
 41     if(x>=k) return query(L[u],L[v],L[lca],L[lca_fa],l,mid,k);
 42     else return query(R[u],R[v],R[lca],R[lca_fa],mid+1,r,k-x);
 43 }
 44 inline int hash(int x){
 45     return lower_bound(b+1,b+1+size,x)-b;
 46 }
 47 int ff(int x){
 48     return fa[x]==x?x:fa[x]=ff(fa[x]);
 49 }
 50 int st[N][17],d[N],vis[N];
 51 void dfs(int u,int father,int root){
 52     st[u][0]=father;
 53     for(int i=1;i<=16;++i)
 54     st[u][i]=st[st[u][i-1]][i-1];
 55     ++sz[root];
 56     d[u]=d[father]+1;
 57     fa[u]=root;
 58     vis[u]=1;
 59     update(rt[father],rt[u],1,size,hash(a[u]));
 60     for(int i=head[u];i;i=Next[i]){
 61         int v=ver[i];
 62         if(v==father) continue;
 63         dfs(v,u,root);
 64     }
 65 }
 66 int LCA(int x,int y){
 67     if(x==y) return x;
 68     if(d[x]<d[y]) swap(x,y);
 69     for(int i=16;i>=0;--i){
 70         if(d[st[x][i]]>=d[y]) x=st[x][i];
 71     }
 72     if(x==y) return x;
 73     for(int i=16;i>=0;--i){
 74         if(st[x][i]!=st[y][i])
 75         x=st[x][i],y=st[y][i];
 76     }
 77     return st[x][0];
 78 }
 79 int main(){
 80     //freopen("testdata.in","r",stdin);
 81     int t=read();
 82     n=read(),m=read(),q=read();
 83     for(int i=1;i<=n;++i)
 84     a[i]=b[i]=read(),fa[i]=i;
 85     sort(b+1,b+1+n);
 86     size=unique(b+1,b+1+n)-b-1;
 87     for(int i=1;i<=m;++i){
 88         int u=read(),v=read();
 89         add(u,v);
 90     }
 91     for(int i=1;i<=n;++i)
 92     if(!vis[i]) dfs(i,0,i);
 93     while(q--){
 94         char ch;int x,y;
 95         while(!isupper(ch=getc()));
 96         x=read()^ans,y=read()^ans;
 97         if(ch=='Q'){
 98             int k=read()^ans;
 99             int lca=LCA(x,y);
100             ans=b[query(rt[x],rt[y],rt[lca],rt[st[lca][0]],1,size,k)];
101             print(ans),*o++='\n';
102         }
103         else{
104             add(x,y);
105             int u=ff(x),v=ff(y);
106             if(sz[u]<sz[v]) swap(x,y),swap(u,v);
107             dfs(y,x,u);
108         }
109     }
110     fwrite(obuf,o-obuf,1,stdout);
111     return 0;
112 }

 

转载于:https://www.cnblogs.com/bztMinamoto/p/9396807.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值