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 }
主席树

 

posted @ 2019-02-17 17:20  杜宇一声  阅读(165)  评论(0编辑  收藏  举报