快要下班了,先贴线段树代码//下班是指从实验室回宿舍了
update:又是线段树维护树直径,写了好几次了,多校写了个换根dp维护树直径,上海A题是线段树维护树直径,这两题的共同点就是:都能比较快速的独立切出来,但是比赛时都没读题…这题线段树写挺无脑的,不讲了,下面讲动态点分治怎么写(点分治比线段树写法多一个log):
我们可以枚举所有点 i i i,优先队列维护经过 i i i的最长链,那么队首元素就是答案,因此我们可以先根据重心建好树,在分治树中,用优先队列 d [ i ] d[i] d[i]存 i i i子树所有点到其父亲的距离,用优先队列 d p [ i ] dp[i] dp[i]存 i i i所有儿子 d [ s o n ] d[son] d[son]的最大值,再多存个0,表示 i i i到 i i i的距离,用一个全局优先队列存所有 d p [ i ] dp[i] dp[i]的最大次大值之和,如果 d p [ i ] dp[i] dp[i]只有一个元素,说明 i i i子树中只有一个可用点,那么规定 d p [ i ] dp[i] dp[i]最大值次大值之和为0,如果 d p [ i ] dp[i] dp[i]为空,那么说明无可用点,规定 d p [ i ] dp[i] dp[i]的最大次大值之和为-1,然后随便搞搞就完了。
线段树代码
#include<bits/stdc++.h>
#define ll long long
#define ls o * 2
#define rs o * 2 + 1
#define mid (l + r) / 2
using namespace std;
const int maxn = 1e5 + 10;
vector<int> G[maxn];
int n, d[maxn * 2][20], dep[maxn], L[maxn], R[maxn], rk[maxn], cnt, tot, pos[maxn];
void dfs(int u, int fa) {
L[u] = ++cnt;
pos[u] = ++tot;
dep[u] = dep[fa] + 1;
d[tot][0] = dep[u];
rk[cnt] = u;
for (int i = 0; i < G[u].size(); i++)
if (G[u][i] != fa) {
dfs(G[u][i], u);
d[++tot][0] = dep[u];
}
R[u] = cnt;
}
void init() {
for (int i = 1; (1 << i) <= tot; i++)
for (int j = 1; j + (1 << i) - 1 <= tot; j++)
d[j][i] = min(d[j][i - 1], d[j + (1 << i - 1)][i - 1]);
}
int LCA(int x, int y) {
int l = pos[x], r = pos[y];
if (l > r)
swap(l, r);
int k = log2(r - l + 1);
return min(d[l][k], d[r - (1 << k) + 1][k]);
}
ll dist(int x, int y) {
int lca = LCA(x, y);
//printf("x = %d y = %d lca = %d\n", x, y, lca);
return dep[x] + dep[y] - lca * 2;
}
struct node {
int x, y;
ll len;
node operator+(const node& t) const {
node tmp = t;
if (x == 0)
return t;
if (t.x == 0)
return node{x, y, len};
if (len > t.len)
tmp = node{x, y, len};
ll dist1 = dist(x, t.x);
ll dist2 = dist(x, t.y);
ll dist3 = dist(y, t.x);
ll dist4 = dist(y, t.y);
if (dist1 > tmp.len)
tmp = node{x, t.x, dist1};
if (dist2 > tmp.len)
tmp = node{x, t.y, dist2};
if (dist3 > tmp.len)
tmp = node{y, t.x, dist3};
if (dist4 > tmp.len)
tmp = node{y, t.y, dist4};
return tmp;
}
} tree[maxn * 4];
void build(int o, int l, int r) {
if (l == r) {
tree[o] = node{rk[l], rk[l], -1};
return;
}
build(ls, l, mid);
build(rs, mid + 1, r);
tree[o] = tree[ls] + tree[rs];
}
void update(int o, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr) {
if (tree[o].x)
tree[o] = node{0, 0, -1};
else
tree[o] = node{rk[l], rk[l], -1};
return;
}
if (ql <= mid)
update(ls, l, mid, ql, qr);
if (qr > mid)
update(rs, mid + 1, r, ql, qr);
tree[o] = tree[ls] + tree[rs];
}
int main() {
int u, v, q, x;
char c;
scanf("%d", &n);
for (int i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
init();
build(1, 1, n);
scanf("%d", &q);
while (q--) {
getchar();
scanf("%c", &c);
if (c == 'G') {
if (!tree[1].x)
puts("-1");
else
printf("%d\n", tree[1].len);
}
else {
scanf("%d", &x);
update(1, 1, n, L[x], L[x]);
}
}
}
动态点分治代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10, inf = 1e9;
struct heap {
priority_queue< int, vector<int>, less<int> > q, del;
int size() {
return q.size() - del.size();
}
void erase(int x) {
del.push(x);
}
int top() {
while (!del.empty() && q.top() == del.top())
q.pop(), del.pop();
if (q.empty())
return -1;
return q.top();
}
void push(int x) {
while (!del.empty() && q.top() == del.top())
q.pop(), del.pop();
q.push(x);
}
int twotop() {
if (!size())
return -1;
else if (size() == 1)
return 0;
int x = top();
erase(x);
int y = top();
push(x);
return x + y;
}
} d[maxn], dp[maxn], ans;
vector<int> G[maxn];
int n, sz[maxn], size, rt, mn, vis[maxn], f[maxn];
int st[maxn * 2][20], id[maxn], dep[maxn], cnt, inv[maxn];
void dfs(int u, int fa) {
dep[u] = dep[fa] + 1;
st[++cnt][0] = dep[u];
id[u] = cnt;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (v != fa) {
dfs(v, u);
st[++cnt][0] = dep[u];
}
}
}
void rmq() {
for (int i = 1; (1 << i) <= cnt; i++)
for (int j = 1; j - 1 + (1 << i) <= cnt; j++)
st[j][i] = min(st[j][i - 1], st[j + (1 << i - 1)][i - 1]);
}
int LCA(int x, int y) {
int l = id[x], r = id[y];
if (l > r)
swap(l, r);
int k = log2(r - l + 1);
return min(st[l][k], st[r + 1 - (1 << k)][k]);
}
int dist(int x, int y) {
return dep[x] + dep[y] - 2 * LCA(x, y);
}
void findrt(int u, int fa) {
sz[u] = 1;
int mx = 0;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (!vis[v] && v != fa) {
findrt(v, u);
sz[u] += sz[v];
mx = max(mx, sz[v]);
}
}
mx = max(mx, size - sz[u]);
if (mx < mn)
mn = mx, rt = u;
}
void solve(int u, int fa, int root) {
int len = dist(u, root);
d[rt].push(len);
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (!vis[v] && v != fa)
solve(v, u, root);
}
}
void divide(int u, int fa) {
f[u] = fa;
vis[u] = 1;
if (fa)
solve(u, 0, fa);
dp[u].push(0);
int tmp = size;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (!vis[v]) {
size = (sz[v] > sz[u]) ? tmp - sz[u] : sz[v];
mn = inf;
findrt(v, 0);
int root = rt;
divide(rt, u);
dp[u].push(d[root].top());
}
}
ans.push(dp[u].twotop());
}
void change(int u, int v) {
if (!f[u])
return;
int len = dist(f[u], v);
ans.erase(dp[f[u]].twotop());
if (d[u].size())
dp[f[u]].erase(d[u].top());
if (inv[v])
d[u].erase(len);
else
d[u].push(len);
if (d[u].size())
dp[f[u]].push(d[u].top());
ans.push(dp[f[u]].twotop());
change(f[u], v);
}
int main() {
int q, u, v;
char c;
scanf("%d", &n);
int num = n;
for (int i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
rmq();
size = n;
mn = inf;
findrt(1, 0);
divide(rt, 0);
scanf("%d", &q);
while (q--) {
getchar();
scanf("%c", &c);
if (c == 'G')
printf("%d\n", ans.top());
else {
scanf("%d", &u);
ans.erase(dp[u].twotop());
if (!inv[u])
dp[u].erase(0);
else
dp[u].push(0);
ans.push(dp[u].twotop());
inv[u] ^= 1;
change(u, u);
}
}
}