主席树 启发式合并bzoj3123: [Sdoi2013]森林

Posted antiquality

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了主席树 启发式合并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

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

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。之后的操作类似。

技术分享图片


题目分析

这个题意已经是非常裸的数据结构题了。我们需要实现的有:只有加边的动态LCA、主席树启发式合并。

本来还想写个内存回收的,但是写完一来发现对效率好像不是很自信;二来看了看觉得空间也还过得去,就没再写回收了。

没有理解为什么森林初始不是全为点的。可能是为了区分我这样的大常数?

话说20s的题交上去刷新一下就返回TLE是什么机制……

  1 #include<bits/stdc++.h>
  2 const int maxn = 800035;
  3 const int maxm = 1600035;
  4 const int maxNode = 20000035;
  5 
  6 struct segNode
  7 {
  8     int l,r,val;
  9 }a[maxNode];
 10 struct Pool
 11 {
 12     int tot;
 13     int newNode()
 14     {
 15         ++tot, a[tot].l = a[tot].r = a[tot].val = 0;
 16         return tot;
 17     }
 18 }node;
 19 char opt[5];
 20 int T,n,m,q,lastans;
 21 int rt[maxn],c[maxn],tmp[maxn],fat[maxn],size[maxn];
 22 int edgeTot,head[maxn],nxt[maxm],edges[maxm];
 23 struct treeStruction
 24 {
 25     int fa[maxn][23],dep[maxn];
 26     void init()
 27     {
 28         memset(fa, 0, sizeof fa);
 29         for (int i=1; i<=n; i++) dep[i] = 1;
 30     }
 31     int lca(int u, int v)
 32     {
 33         if (dep[u] < dep[v]) std::swap(u, v);
 34         for (int i=17; i>=0; i--)
 35             if (dep[fa[u][i]] >= dep[v]) u = fa[u][i];
 36         if (u==v) return u;
 37         for (int i=17; i>=0; i--)
 38             if (fa[u][i]!=fa[v][i])
 39                 u = fa[u][i], v = fa[v][i];
 40         return fa[u][0];
 41     }
 42 }tre;
 43 
 44 int read()
 45 {
 46     char ch = getchar();
 47     int num = 0, fl = 1;
 48     for (; !isdigit(ch); ch=getchar())
 49         if (ch==-) fl = -1;
 50     for (; isdigit(ch); ch=getchar())
 51         num = (num<<1)+(num<<3)+ch-48;
 52     return num*fl;
 53 }
 54 int find(int x)
 55 {
 56     while (x!=fat[x]) x = fat[x];
 57     return x;
 58 }
 59 void update(int &rt, int pre, int L, int R, int c)
 60 {
 61     rt = node.newNode();
 62     a[rt] = a[pre], ++a[rt].val;
 63     if (L==R) return;
 64     int mid = (L+R)>>1;
 65     if (c <= mid) update(a[rt].l, a[pre].l, L, mid, c);
 66     else update(a[rt].r, a[pre].r, mid+1, R, c);
 67 }
 68 int query(int u, int v, int lca, int fa, int L, int R, int k)
 69 {
 70     if (L==R) return L;
 71     int mid = (L+R)>>1, val = a[a[u].l].val+a[a[v].l].val-a[a[lca].l].val-a[a[fa].l].val;
 72     if (k <= val) return query(a[u].l, a[v].l, a[lca].l, a[fa].l, L, mid, k);
 73     return query(a[u].r, a[v].r, a[lca].r, a[fa].r, mid+1, R, k-val);
 74 }
 75 void connect(int x, int fat)
 76 {
 77     tre.dep[x] = tre.dep[fat]+1, tre.fa[x][0] = fat;
 78     update(rt[x], rt[fat], 1, tmp[0], c[x]);
 79     for (int i=1; i<=17; i++)
 80         tre.fa[x][i] = tre.fa[tre.fa[x][i-1]][i-1];
 81     for (int i=head[x]; i!=-1; i=nxt[i])
 82         if (fat!=edges[i]) connect(edges[i], x);
 83 }
 84 void addedge(int u, int v)
 85 {
 86     int fu = find(u), fv = find(v);
 87     if (size[fu] > size[fv]) std::swap(fu, fv), std::swap(u, v);
 88     fat[fu] = fv, size[fv] += size[fu], connect(u, v);
 89     edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot;
 90     edges[++edgeTot] = u, nxt[edgeTot] = head[v], head[v] = edgeTot;
 91 }
 92 void discretization()
 93 {
 94     std::sort(tmp+1, tmp+n+1);
 95     tmp[0] = std::unique(tmp+1, tmp+n+1)-tmp-1;
 96     for (int i=1; i<=n; i++)
 97     {
 98         c[i] = std::lower_bound(tmp+1, tmp+tmp[0]+1, c[i])-tmp;
 99         update(rt[i], 0, 1, tmp[0], c[i]);
100     }
101 }
102 int main()
103 {
104     T = read();
105     memset(rt, 0, sizeof rt);
106     memset(head, -1, sizeof head);
107     n = read(), m = read(), q = read();
108     tre.init();
109     node.tot = lastans = edgeTot = 0;
110     for (int i=1; i<=n; i++)
111         tmp[i] = c[i] = read(), fat[i] = i, size[i] = 1;
112     discretization();
113     for (int i=1; i<=m; i++) addedge(read(), read());
114     for (int i=1; i<=q; i++)
115     {
116         scanf("%s",opt);
117         if (opt[0]==Q){
118             int u = read()^lastans, v = read()^lastans;
119             int k = read()^lastans, lca = tre.lca(u, v);
120             lastans = tmp[query(rt[u], rt[v], rt[lca], rt[tre.fa[lca][0]], 1, tmp[0], k)];
121             printf("%d
",lastans);
122         }else addedge(read()^lastans, read()^lastans);
123     }
124     return 0;
125 }

 

 

END

以上是关于主席树 启发式合并bzoj3123: [Sdoi2013]森林的主要内容,如果未能解决你的问题,请参考以下文章

[bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT

bzoj 3123: [Sdoi2013]森林

BZOJ 3123 SDOI2013 森林

BZOJ 3123 [Sdoi2013]森林

bzoj3123: [Sdoi2013]森林

p3302 [SDOI2013]森林(树上主席树+启发式合并)