【主席树 启发式合并】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\n",lastans); 122 }else addedge(read()^lastans, read()^lastans); 123 } 124 return 0; 125 }
END