BZOJ 3123 SDOI2013 森林 启发式合并+主席树
题意:
给出一个森林,强制在线,支持动态加边和询问链上第k大,保证加边后图仍然是森林。
分析:
有一点经验的选手都清楚,动态加边想LCT,第K大想主席树,于是有大爷LCT+主席树秒了%%%(我并不会)
观察问题,出题人在这里摆下了一个疑阵,故意引我们向link-cut tree上去思考,但是,我们发现,这个招数未免太过手下留情,如果出题人想要让我们非用LCT不可呢,不妨加一个删边操作,可是没有,所以我们判断这里多半有诈!
加边操作,可以看作是合并连通块信息,所以我们可以想到启发式合并(在合并的过程中重构倍增lca数组,修改主席树),对于询问,我们可以用主席树处理。
这道题需要对启发式合并,LCA,主席树算法的灵活运用,不失为一道数据结构好题。
代码:
1 #include<bits/stdc++.h> 2 #define ms(a,x) memset(a,x,sizeof(a)) 3 using namespace std; 4 const int N=1000005,inf=1e9; 5 struct node{int y,nxt;}e[N*2]; 6 int o,n,m,ans=0,c=1,cnt=0,rt[N],ls[N*5],rs[N*5]; 7 int siz[N*5],sm[N],f[N],nm[N],fa[N][20],d[N],t; 8 int h[N];bool vis[N];char s[10]; 9 int get(int x){ 10 return f[x]==x?x:f[x]=get(f[x]); 11 } void add(int x,int y){ 12 e[++c]=(node){y,h[x]};h[x]=c; 13 e[++c]=(node){x,h[y]};h[y]=c; 14 } int lca(int x,int y){ 15 if(d[x]<d[y]) swap(x,y); 16 int l=d[x]-d[y]; 17 for(int i=19;~i;i--) 18 if((1<<i)&l) x=fa[x][i]; 19 if(x==y) return x; 20 for(int i=19;~i;i--) 21 if(fa[x][i]!=fa[y][i]) 22 x=fa[x][i],y=fa[y][i]; 23 return fa[x][0]; 24 } void update(int x,int &nw,int l,int r,int v){ 25 if(!nw) nw=++cnt;siz[nw]=siz[x]+1; 26 if(l==r) return ;int mid=l+r>>1; 27 if(v<=mid) rs[nw]=rs[x], 28 update(ls[x],ls[nw],l,mid,v); 29 else ls[nw]=ls[x], 30 update(rs[x],rs[nw],mid+1,r,v);return ; 31 } int query(int x,int y,int u,int v,int l,int r,int w){ 32 if(l==r) return l;int mid=l+r>>1,re; 33 re=siz[ls[x]]+siz[ls[y]]-siz[ls[u]]-siz[ls[v]]; 34 if(w<=re) return 35 query(ls[x],ls[y],ls[u],ls[v],l,mid,w); 36 else return 37 query(rs[x],rs[y],rs[u],rs[v],mid+1,r,w-re); 38 } void dfs(int x,int f){ 39 vis[x]=1;d[x]=d[f]+1;fa[x][0]=f; 40 for(int i=1;i<=19;i++) 41 fa[x][i]=fa[fa[x][i-1]][i-1]; 42 update(rt[f],rt[x],0,inf,nm[x]); 43 for(int i=h[x],y;~i;i=e[i].nxt) 44 if((y=e[i].y)!=f) dfs(y,x); 45 } void merge(int x,int y){ 46 int fx=get(x),fy=get(y); 47 f[fx]=fy;sm[fy]+=sm[fx]; 48 } int main(){ 49 ms(h,-1);ms(vis,0);ms(rt,0); 50 scanf("%d%d%d%d",&o,&n,&m,&t); 51 for(int i=1;i<=n;i++) 52 scanf("%d",&nm[i]),f[i]=i,sm[i]=1; 53 for(int i=1,x,y;i<=m;i++) 54 scanf("%d%d",&x,&y),add(x,y),merge(x,y); 55 for(int i=1;i<=n;i++) 56 if(!vis[i]) dfs(i,0); 57 for(int i=1,x,y,z;i<=t;i++){ 58 scanf("%s",s); 59 if(s[0]=='Q'){ 60 scanf("%d%d%d",&x,&y,&z); 61 x^=ans;y^=ans;z^=ans; 62 int nw=lca(x,y);ans= 63 query(rt[x],rt[y],rt[nw],rt[fa[nw][0]], 64 0,inf,z);printf("%d\n",ans); 65 } else{ 66 scanf("%d%d",&x,&y); 67 x^=ans;y^=ans; 68 int fx=get(x),fy=get(y); 69 if(sm[fx]>sm[fy]) swap(y,x); 70 add(x,y);merge(x,y);dfs(x,y); 71 } 72 } return 0; 73 }