BZOJ3123:[SDOI2013]森林(主席树,启发式合并)

Description

Input

第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。
第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。
 接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。

Output

对于每一个第一类操作,输出一个非负整数表示答案。

Sample Input

1
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3 Q 3 5 1
Q 10 0 0
L 5 4
L 3 2 L 0 7
Q 9 2 5 Q 6 1 6

Sample Output

2
2
1
4
2

HINT

对于第一个操作 Q 8 7 3,此时 lastans=0,所以真实操作为Q 8^0 7^0 3^0,也即Q 8 7 3。点8到点7的路径上一共有5个点,其权值为4 1 1 2 4。这些权值中,第三小的为 2,输出 2,lastans变为2。对于第二个操作 Q 3 5 1 ,此时lastans=2,所以真实操作为Q 3^2 5^2 1^2 ,也即Q 1 7 3。点1到点7的路径上一共有4个点,其权值为 1 1 2 4 。这些权值中,第三小的为2,输出2,lastans变为 2。之后的操作类似。

Solution

可以发现没有连边那个操作就是裸的把主席树放到树上跑……QAQ 具体操作可以看我这篇博客

然后又发现只有连边没有删边……那么就可以直接每次连边就启发式合并两棵树,对小的那颗暴力全部重建主席树。复杂度$nlog^2n$

Code

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<algorithm>
  5 #define N (80009)
  6 using namespace std;
  7 
  8 struct Sgt{int ls,rs,val;}Segt[N<<7];
  9 struct Edge{int to,next;}edge[N<<1];
 10 int head[N],num_edge;
 11 int testcase,n,m,q,u,v,num,x,y,k,lca,sgt_num,lastans;
 12 int Root[N],a[N],b[N],Depth[N],f[N][18],vis[N],Top[N],Size[N];
 13 char opt[2];
 14 
 15 int getid(int x) {return lower_bound(b+1,b+n+1,x)-b;}
 16 
 17 void add(int u,int v)
 18 {
 19     edge[++num_edge].to=v;
 20     edge[num_edge].next=head[u];
 21     head[u]=num_edge;
 22 }
 23 
 24 int Update(int pre,int l,int r,int x)
 25 {
 26     int now=++sgt_num;
 27     Segt[now].val=Segt[pre].val+1;
 28     Segt[now].ls=Segt[pre].ls;
 29     Segt[now].rs=Segt[pre].rs;
 30     if (l==r) return now;
 31     int mid=(l+r)>>1;
 32     if (x<=mid) Segt[now].ls=Update(Segt[now].ls,l,mid,x);
 33     else Segt[now].rs=Update(Segt[now].rs,mid+1,r,x);
 34     return now;
 35 }
 36 
 37 int Build(int l,int r)
 38 {
 39     int now=++sgt_num;
 40     if (l==r) return now;
 41     int mid=(l+r)>>1;
 42     Segt[now].ls=Build(l,mid);
 43     Segt[now].rs=Build(mid+1,r);
 44     return now;
 45 }
 46 
 47 void DFS(int x,int fa,int top)
 48 {
 49     Size[top]++; Depth[x]=Depth[fa]+1;
 50     f[x][0]=fa; Top[x]=top; vis[x]=true;
 51     for (int i=1; i<=17; ++i)
 52         f[x][i]=f[f[x][i-1]][i-1];
 53     int id=getid(a[x]);
 54     Root[x]=Update(Root[fa],1,num,id);
 55     for (int i=head[x]; i; i=edge[i].next)
 56         if (edge[i].to!=fa)
 57         {
 58             DFS(edge[i].to,x,top);
 59             Size[x]+=Size[edge[i].to];
 60         }
 61 }
 62 
 63 int LCA(int x,int y)
 64 {
 65     if (Depth[x]<Depth[y]) swap(x,y);
 66     for (int i=17; i>=0; --i)
 67         if (Depth[f[x][i]]>=Depth[y]) x=f[x][i];
 68     if (x==y) return x;
 69     for (int i=17; i>=0; --i)
 70         if (f[x][i]!=f[y][i]) x=f[x][i], y=f[y][i];
 71     return f[x][0];
 72 }
 73 
 74 int Query(int u,int v,int lca,int flca,int l,int r,int k)
 75 {
 76     if (l==r) return b[l];
 77     int mid=(l+r)>>1;
 78     int x=Segt[Segt[u].ls].val+Segt[Segt[v].ls].val-Segt[Segt[lca].ls].val-Segt[Segt[flca].ls].val;
 79     if (k<=x) return Query(Segt[u].ls,Segt[v].ls,Segt[lca].ls,Segt[flca].ls,l,mid,k);
 80     else return Query(Segt[u].rs,Segt[v].rs,Segt[lca].rs,Segt[flca].rs,mid+1,r,k-x);
 81 }
 82 
 83 int main()
 84 {
 85     scanf("%d",&testcase);
 86     scanf("%d%d%d",&n,&m,&q);
 87     for (int i=1; i<=n; ++i)
 88         scanf("%d",&a[i]), b[i]=a[i];
 89     sort(b+1,b+n+1);
 90     num=unique(b+1,b+n+1)-b-1;
 91     Root[0]=Build(1,num);
 92     for (int i=1; i<=m; ++i)
 93     {
 94         scanf("%d%d",&u,&v);
 95         add(u,v); add(v,u);
 96     }
 97     for (int i=1; i<=n; ++i)
 98         if (!vis[i]) DFS(i,0,i);
 99     for (int Q=1; Q<=q; ++Q)
100     {
101         scanf("%s",opt);
102         if (opt[0]=='Q')
103         {
104             scanf("%d%d%d",&x,&y,&k);
105             x^=lastans; y^=lastans; k^=lastans;
106             int lca=LCA(x,y);
107             int ans=Query(Root[x],Root[y],Root[lca],Root[f[lca][0]],1,num,k);
108             printf("%d\n",ans); lastans=ans;
109         }
110         else
111         {
112             scanf("%d%d",&x,&y);
113             x^=lastans; y^=lastans;
114             add(x,y); add(y,x);
115             if (Size[Top[x]]<Size[Top[y]]) DFS(x,y,Top[y]);
116             else DFS(y,x,Top[x]);
117         }
118     }
119 }
posted @ 2018-12-07 16:23  Refun  阅读(221)  评论(0编辑  收藏  举报