You are given a tree (an acyclic undirected connected graph) with N nodes, and nodes numbered 1,2,3…,N. Each edge has an integer value assigned to it(note that the value can be negative). Each node has a color, white or black. We define dist(a, b) as the sum of the value of the edges on the path from node a to node b.
All the nodes are white initially.
We will ask you to perform some instructions of the following form:
C a : change the color of node a.(from black to white or from white to black)
A : ask for the maximum dist(a, b), both of node a and node b must be white(a can be equal to b). Obviously, as long as there is a white node, the result will always be non negative.
Input
In the first line there is an integer N (N <= 100000)
In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between a, b of value c (-1000 <= c <= 1000)
In the next line, there is an integer Q denotes the number of instructions (Q <= 100000)
In the next Q lines, each line contains an instruction “C a” or “A”
Output
For each “A” operation, write one integer representing its result. If there is no white node in the tree, you should write “They have disappeared.”.
Example
Input:
3
1 2 1
1 3 1
7
A
C 1
A
C 2
A
C 3
A
Output:
2
2
0
They have disappeared.
边分治、堆 - AC
先考虑不更改的。
边分治处理与树的路径有关的问题。找到一条中心边,删掉它之后树分成两半,使两半的大小尽可能均匀,达到分治降低复杂度的目的。路径分为经过中心边和不经过的,前者是我们要考虑的;对于后者,递归分治处理。
与中心边相连的两个节点p1,p2分别作为两棵子树的根。经过中心边的最长路径,就是左边子树中白色节点到p1的最长距离,加上右边的,加上中心边。
本来是整个树。分成两半。对于分出来的每个子树,它的答案是由它再分出来的两个子树中的数据处理得到。然后再往上传,传到最大的那个子树,也就是整棵树。这很像是线段树。同样地,边分治处理的这些“子树”要开4倍空间。
不过,有时找不到想要的中心边。比如在菊花图上。所以要加虚点,将多叉树变成二叉树,虚边权为0。不能使用孩子兄弟表示法,那会改变两点间距离。
据上文,要维护“子树中白色节点到根的最长距离”。节点颜色会变。黑变白,考虑新的白色节点对这个最长距离的贡献;白变黑,删除它的贡献。为此要记录所有节点到根的距离,将白色的加入到堆中,颜色作为删除懒标记。
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn).
M A X N = 1 0 5 MAXN=10^5 MAXN=105,但我得把它开到 1 0 6 10^6 106才能不RE,不知道哪里写错了。
struct DNode {
int u, d;
DNode(int _u, int _d): u(_u), d(_d){}
bool operator < (const DNode &x) const {
return x.d > d;
}
};
struct Node {
int rt, w, ans, lc, rc;
priority_queue<DNode> q;
Node(): lc(-1), rc(-1){}
} t[MAXN << 3];
int m;
int n, n1, siz[MAXN << 1], tot, mx, mide, q;
int head[MAXN << 1], to[MAXN << 2], len[MAXN << 2], nxt[MAXN << 2], js;
int head1[MAXN << 1], to1[MAXN << 2], len1[MAXN << 2], nxt1[MAXN << 2], js1;
bool mark[MAXN << 1], vis[MAXN << 2];
char op[3];
void add(int u, int v, int w) {
to[js] = v; len[js] = w; nxt[js] = head[u]; head[u] = js++;
}
void add1(int u, int v, int w) {
to1[js1] = v; len1[js1] = w; nxt1[js1] = head1[u]; head1[u] = js1++;
}
void rebuild(int u, int par) {
int fa = 0;
for (int i = head[u]; ~i; i = nxt[i]) {
int v = to[i], w = len[i];
if (v == par) continue;
if (!fa) {
add1(u, v, w); add1(v, u, w);
fa = u;
}
else {
mark[++n1] = 1;
add1(fa, n1, 0); add1(n1, fa, 0);
fa = n1;
add1(fa, v, w); add1(v, fa, w);
}
rebuild(v, u);
}
}
void pushup(int i) {
t[i].ans = -1;
while (!t[i].q.empty() && mark[t[i].q.top().u]) t[i].q.pop();
int lc = t[i].lc, rc = t[i].rc;
if (lc == -1 && rc == -1) {
if (!mark[t[i].rt]) t[i].ans = 0;
}
else {
ckmax(t[i].ans, max(t[lc].ans, t[rc].ans));
if (!t[lc].q.empty() && !t[rc].q.empty()) {
ckmax(t[i].ans, t[lc].q.top().d + t[rc].q.top().d + t[i].w);
}
}
}
void setmide(int u, int x, int i, int dep) {
siz[u] = 1;
add(u, i, dep);
if (!mark[u]) t[i].q.push(DNode(u, dep));
for (int j = head1[u]; ~j; j = nxt1[j]) {
int v = to1[j], w = len1[j];
if (j == (x ^ 1) || vis[j]) continue;
setmide(v, j, i, dep + w);
siz[u] += siz[v];
}
if (ckmin(mx, max(siz[u], tot - siz[u]))) mide = x;
}
void solve(int i, int u) {
t[i].rt = u;
tot = siz[u], mx = INF; setmide(u, -1, i, 0);
if (~mide) {
int p1 = to1[mide], p2 = to1[mide ^ 1];
siz[p2] = siz[u] - siz[p1];
t[i].lc = m++, t[i].rc = m++;
t[i].w = len1[mide];
vis[mide] = vis[mide ^ 1] = true;
solve(t[i].lc, p1);
solve(t[i].rc, p2);
}
pushup(i);
}
void modify(int u) {
mark[u] ^= 1;
for (int i = head[u]; ~i; i = nxt[i]) {
int v = to[i], w = len[i];
if (!mark[u]) t[v].q.push(DNode(u, w));
pushup(v);
}
}
int main() {
memset(head, -1, sizeof(head));
memset(head1, -1, sizeof(head1));
scanf("%d", &n);
for (int i = 1; i < n; ++i) {
int a, b, c; scanf("%d%d%d", &a, &b, &c);
add(a, b, c); add(b, a, c);
}
n1 = n; rebuild(1, 0);
memset(head, -1, sizeof(head)); js = 0;
siz[1] = n1; solve(m++, 1);
scanf("%d", &q);
while (q--) {
scanf("%s", op);
if (op[0] == 'A') {
if (~t[0].ans) printf("%d\n", t[0].ans);
else printf("They have disappeared.\n");
}
else {
int tmp; scanf("%d", &tmp);
modify(tmp);
}
}
return 0;
}