【SDOI2013】森林

链接

先考虑对于一棵树进行路径查询,当然可以树链剖分,但没必要。

对于一个询问 [ x , y ] ,可以转化为 [ x , root ] + [ y , root ] - 2 [ lca , root ] + lca,即 [ x , root ] + [ y , root ] - [ lca , root ] - [ fa [ lca ] , root ]

所以只要统计节点到根节点的信息就可以了,求第k小,显然要用主席树。

我们知道,主席树的基本思想是前缀和,在序列上时,以前一个为pre;在树上时,只要以这个节点的父亲为pre就可以了。

这样就解决了询问。

对于连边,可以启发式合并。简而言之就是小树往大树上连。

启发式合并中,每个节点只有在当前size较小时才会被合并,每次合并后体积至少扩大为原来的两倍。所以总复杂度是O(NlogN)。因为更新倍增数组和插入是O(logN)的,所以带了两个log,还是可以接受的。

最后注意要离散化,数组要开大。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<string>
  4 #include<cstring>
  5 #include<cstdlib>
  6 using namespace std;
  7 
  8 int read(){
  9     int x=0;char ch=getchar();
 10     while(ch<'0'||ch>'9')ch=getchar();
 11     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
 12     return x;
 13 }
 14 
 15 const int N=80005;
 16 
 17 int testcase,n,m,t,ans=0;
 18 char op[3];
 19 int x,y,k;
 20 
 21 struct node{
 22     int y,nxt;
 23 }e[N*4];
 24 int h[N],tot=0;
 25 void ad(int x,int y){
 26     ++tot;e[tot].y=y;e[tot].nxt=h[x];h[x]=tot;
 27 }
 28 
 29 int fa[N];
 30 int find(int x){
 31     return x==fa[x]?x:fa[x]=find(fa[x]);
 32 }
 33 
 34 int root[N],cnt=0;;
 35 int val[N],b[N],len;
 36 struct Tree{
 37     int ls,rs,sz;
 38 }tr[N*600];
 39 int build(int l,int r){
 40     int rt=++cnt;
 41     tr[rt].sz=0;
 42     if(l==r)return rt;
 43     int mid=(l+r)>>1;
 44     tr[rt].ls=build(l,mid);
 45     tr[rt].rs=build(mid+1,r);
 46     return rt;
 47 }
 48 int sz[N],st[N][18],dep[N],vis[N];
 49 int Hash(int x){
 50     return lower_bound(b+1,b+len+1,x)-b;
 51 }
 52 void insert(int &now,int pre,int l,int r,int x){
 53     now=++cnt;
 54     tr[now]=tr[pre];++tr[now].sz;
 55     if(l==r)return;
 56     int mid=(l+r)>>1;
 57     if(x<=mid)insert(tr[now].ls,tr[pre].ls,l,mid,x);
 58     else insert(tr[now].rs,tr[pre].rs,mid+1,r,x);
 59 }
 60 void dfs(int x,int father,int rt){
 61     dep[x]=dep[father]+1;
 62     st[x][0]=father;++sz[rt];
 63     vis[x]=1;fa[x]=father;
 64     for(int j=1;j<=17;++j)st[x][j]=st[st[x][j-1]][j-1];
 65     insert(root[x],root[father],1,len,Hash(val[x]));
 66     for(int i=h[x];i;i=e[i].nxt){
 67         int y=e[i].y;
 68         if(y==father)continue;
 69         dfs(y,x,rt);
 70     }
 71 }
 72 int LCA(int x,int y){
 73     if(dep[x]<dep[y])swap(x,y);
 74     for(int j=17;j>=0;--j)if(dep[st[x][j]]>=dep[y])x=st[x][j];
 75     if(x==y)return x;
 76     for(int j=17;j>=0;--j){
 77         if(st[x][j]!=st[y][j])x=st[x][j],y=st[y][j];
 78     }
 79     return st[x][0];
 80 }
 81 int ask(int x,int y,int lca,int flca,int l,int r,int k){
 82     if(l==r)return b[l];
 83     int lsz=tr[tr[x].ls].sz+tr[tr[y].ls].sz-tr[tr[lca].ls].sz-tr[tr[flca].ls].sz;
 84     int mid=(l+r)>>1;
 85     if(k<=lsz)return ask(tr[x].ls,tr[y].ls,tr[lca].ls,tr[flca].ls,l,mid,k);
 86     return ask(tr[x].rs,tr[y].rs,tr[lca].rs,tr[flca].rs,mid+1,r,k-lsz);
 87 }
 88 
 89 int main(){
 90     testcase=read();n=read();m=read();t=read();
 91     for(int i=1;i<=n;++i){
 92         val[i]=read();b[i]=val[i];fa[i]=i;
 93     }
 94     sort(b+1,b+n+1);
 95     len=unique(b+1,b+n+1)-b-1;
 96     while(m--){
 97         x=read();y=read();
 98         ad(x,y);ad(y,x);
 99     }
100     root[0]=build(1,len);
101     for(int i=1;i<=n;++i){
102         if(!vis[i])dfs(i,0,i),fa[i]=i;
103     }
104     while(t--){
105         scanf("%s",op);
106         x=read();y=read();
107         x^=ans,y^=ans;
108         if(op[0]=='L'){
109             ad(x,y);ad(y,x);
110             int fx=find(x),fy=find(y);
111             if(sz[fx]>sz[fy]){
112                 swap(x,y);swap(fx,fy);
113             }
114             dfs(x,y,fy);
115         }
116         else {
117             k=read();k^=ans;
118             int lca=LCA(x,y);
119             ans=ask(root[x],root[y],root[lca],root[st[lca][0]],1,len,k);
120             printf("%d
",ans);
121         }
122     }
123 }
原文地址:https://www.cnblogs.com/chiyo/p/11391362.html