SDOI 2013森林
Posted awhitewall
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDOI 2013森林相关的知识,希望对你有一定的参考价值。
博主的 BiBi 时间
简直不敢相信自己去年 (9) 月学过主席树。。。真的一点印象都没了(真的太菜了)。
另外,这题有个坑点:(testcase) 是数据编号,不是数据组数!
Solution
主席树一般是处理区间第几大/小的问题。然而这次的场景转移到了树上。
我们可以让 (rt[u]) 在 (rt[fa[u]]) 的基础上建树,这样就可以用 (sum[u]+sum[v]-sum[lca(u,v)]-sum[fa[lca(u,v)]]) 来表示这个路径的某种数值的个数。这里的数值离散化处理就行了。
加边操作我们就用启发式合并。每次选择树的大小较小的重建。
证明一下启发式合并的复杂度。我们对于每个点考虑,考虑一直合并上去的情况(启发式合并就是更改大小较小的那一坨,所以它的复杂度是取决于小坨的大小而不是大坨的),因为是合并上去(这是小坨),合并之后整个坨的大小大于等于小坨的大小 (*2)。所以这个点总共最多合并 (logn) 次,又因为是每个点考虑的,其实这个点的合并次数就是这个点的复杂度,总复杂度我们累加即可:(O(nlogn))。
我们算一下空间复杂度。首先我们初始建树是每个点都会建一棵树,每棵树最多加 (logn) 个点,所以这个空间复杂度为 (S(nlogn))。
关于后面重建的空间复杂度。之前的是 (nlogn) 的重建次数(证明在启发式合并证明),每次重建最多加 (logn) 个点,所以空间复杂度 (S(nlogn^2))。
总时间复杂度应该是 (O(nlogn^2))。
博主蒟蒻,如有错误请在评论区指出,我会在第一时间更改。
Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 8e4 + 5;
int n, m, q, a[N], b[N], len, cnt, head[N], nxt[N << 2], to[N << 2], sz, lc[N * 276], rc[N * 276], sum[N * 276], rt[N], siz[N], dep[N], f[N][18], p[5], lastans, root[N];
bool vis[N];
int read() {
int x = 0, f = 1; char s;
while((s = getchar()) < ‘0‘ || s > ‘9‘) if(s == ‘-‘) f = -1;
while(s >= ‘0‘ && s <= ‘9‘) {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
return x * f;
}
void addEdge(const int u, const int v) {
nxt[++ cnt] = head[u], to[cnt] = v, head[u] = cnt;
}
void update(int &o, const int fa, const int l, const int r, const int p) {
if(l > p || r < p) return;
o = ++ sz; lc[o] = lc[fa], rc[o] = rc[fa], sum[o] = sum[fa] + 1;
if(l == r) return;
int mid = l + r >> 1;
update(lc[o], lc[fa], l, mid, p); update(rc[o], rc[fa], mid + 1, r, p);
}
void dfs(const int u, const int fa, const int Root) {
root[u] = Root; vis[u] = siz[u] = 1; f[u][0] = fa; dep[u] = dep[fa] + 1;
update(rt[u], rt[fa], 1, len, a[u]);
for(int i = 1; (1 << i) <= dep[u]; ++ i) f[u][i] = f[f[u][i - 1]][i - 1];
for(int i = head[u]; i; i = nxt[i]) {
int v = to[i];
if(v == fa) continue;
dfs(v, u, Root);
siz[u] += siz[v];
}
}
int lca(int u, int v) {
if(dep[u] > dep[v]) swap(u, v);
int d = dep[v] - dep[u];
for(int i = 0; (1 << i) <= d; ++ i) if((1 << i) & d) v = f[v][i];
if(u == v) return u;
for(int i = 16; ~i; -- i)
if(f[u][i] != f[v][i] && (1 << i) <= dep[v]) u = f[u][i], v = f[v][i];
return f[u][0];
}
int query(const int l, const int r, const int k) {
if(l == r) return l;
int x = sum[lc[p[1]]] + sum[lc[p[2]]] - sum[lc[p[3]]] - sum[lc[p[4]]];
int mid = l + r >> 1;
if(x >= k) {
for(int i = 1; i <= 4; ++ i) p[i] = lc[p[i]];
return query(l, mid, k);
}
else {
for(int i = 1; i <= 4; ++ i) p[i] = rc[p[i]];
return query(mid + 1, r, k - x);
}
}
void init() {
sz = cnt = lastans = 0;
memset(vis, 0, sizeof vis);
memset(head, 0, sizeof head);
}
int main() {
int u, v, k, T = read(); char s[10];
T = 1;
for(; T; -- T) {
n = read(), m = read(), q = read(); init();
for(int i = 1; i <= n; ++ i) a[i] = b[i] = read();
sort(b + 1, b + n + 1);
len = unique(b + 1, b + n + 1) - b - 1;
for(int i = 1; i <= n; ++ i) a[i] = lower_bound(b + 1, b + len + 1, a[i]) - b;
for(int i = 1; i <= m; ++ i) {
u = read(), v = read();
addEdge(u, v), addEdge(v, u);
}
for(int i = 1; i <= n; ++ i) if(! vis[i]) dfs(i, 0, i);
while(q --) {
scanf("%s", s);
if(s[0] == ‘Q‘) {
u = read() ^ lastans, v = read() ^ lastans, k = read() ^ lastans;
int LCA = lca(u, v);
p[1] = rt[u], p[2] = rt[v], p[3] = rt[LCA], p[4] = rt[f[LCA][0]];
printf("%d
", lastans = b[query(1, len, k)]);
}
else {
u = read() ^ lastans, v = read() ^ lastans;
if(siz[root[u]] < siz[root[v]]) swap(u, v);
siz[root[u]] += siz[root[v]];
addEdge(u, v), addEdge(v, u);
dfs(v, u, root[u]);
}
}
}
return 0;
}
/*
1
20 12 20
412060525 42425138 67114752 160822495 201962681 926214957 380263349 733667141 869039239 641017702 154667400 461702107 438851950 176272938 209229857 985208975 762952138 936593832 409183276 999506034
2 17
4 1
15 3
3 10
9 10
7 16
19 15
13 2
6 2
3 14
7 18
8 15
Q 6 17 2
Q 762952152 762952154 762952139
L 380263329 380263352
L 380263357 380263333
Q 380263356 380263359 380263348
L 641017709 641017703
L 641017716 641017700
Q 641017716 641017704 641017698
Q 380263359 380263357 380263345
L 733667140 733667136
L 733667150 733667156
L 733667145 733667142
Q 733667149 733667145 733667140
Q 67114772 67114761 67114759
Q 733667145 733667159 733667142
Q 380263359 380263356 380263351
Q 869039233 869039232 869039237
Q 380263359 380263345 380263356
Q 733667136 733667140 733667143
Q 412060537 412060516 412060519
*/
以上是关于SDOI 2013森林的主要内容,如果未能解决你的问题,请参考以下文章