题目描述
给出一棵边带权的节点数量为n的树,初始树上所有节点都是白色。有两种操作:
C x,改变节点x的颜色,即白变黑,黑变白
A,询问树中最远的两个白色节点的距离,这两个白色节点可以重合(此时距离为0)。
输入输出格式
输入格式:
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 <= 200000)
In the next Q lines, each line contains an instruction "C a" or "A"
输出格式:
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.".
输入输出样例
捉迷藏的升级版,做法见:传送门。只是要注意边权可以为负,所以初值要赋值-inf。
第一次见这个题应该是在半年前了,外出集训看到这道题,根本不知所措。今天终于把这坑了半年的题填了。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
struct edge {
int v, w, next;
}e[maxn << 1];
int head[maxn], cnt, tot, ans;
void adde(const int &u, const int &v, const int &w) {
e[++cnt] = (edge) {v, w, head[u]};
head[u] = cnt;
}
struct Heap {
priority_queue<int > M, D;
void push(int x) {M.push(x);}
void del(int x) {D.push(x);}
void pop() {
while(!M.empty() && !D.empty() && M.top() == D.top())
M.pop(), D.pop();
M.pop();
}
int top() {
while(!M.empty() && !D.empty() && M.top() == D.top())
M.pop(), D.pop();
return M.empty() ? -inf : M.top();
}
int Qms() {
int mx1 = top(), mx2, ans;
if(mx1 == -inf) return 0;
pop(), mx2 = top();
if(mx2 == -inf) return push(mx1), 0;
return push(mx1), mx1 + mx2;
}
} Ans[maxn], Nd[maxn], All;
int size[maxn], mx[maxn], G, vis[maxn];
void FG(int u, int f, int & G, int tot) {
size[u] = 1, mx[u] = 0;
for(register int i = head[u]; i; i = e[i].next) {
int v = e[i].v;
if(vis[v] || v == f) continue;
FG(v, u, G, tot), size[u] += size[v];
mx[u] = max(mx[u], size[v]);
}
mx[u] = max(mx[u], tot - size[u]);
if(mx[u] < mx[G]) G = u;
}
int LG[maxn], fa[maxn], lyr[maxn], Dp[maxn][22], Tp[maxn], Ap[maxn];
void GetInit(int u, int f, int G, int L, int w) {
size[u] = 1;
Dp[u][L] = w, Nd[G].push(w);
for(register int i = head[u]; i; i = e[i].next) {
int v = e[i].v;
if(vis[v] || v == f) continue;
GetInit(v, u, G, L, w + e[i].w);
size[u] += size[v];
}
}
void solve(int u, int rt, int L, int fw) {
int v, tmp;
GetInit(rt, 0, u, L, fw), vis[u] = 1, lyr[u] = L;
for(register int i = head[u]; i; i = e[i].next) {
v = e[i].v;
if(vis[v]) continue;
G = 0, FG(v, 0, G, size[v]), tmp = G;
fa[G] = u, solve(G, v, L + 1, e[i].w);
Tp[tmp] = Nd[tmp].top();
Ans[u].push(Tp[tmp]);
}
Ans[u].push(0);
All.push(Ap[u] = Ans[u].Qms());
}
void CG(int u) {
if(!LG[u]) ++tot, LG[u] = 1, Ans[u].del(0);
else --tot, LG[u] = 0, Ans[u].push(0);
int tmp, p = u, as = Ans[u].Qms(), fp = fa[p];
if(Ap[u] != as) All.push(as), All.del(Ap[u]), Ap[u] = as;
while(fp) {
if(!LG[u]) Nd[p].push(Dp[u][lyr[p]]);
else Nd[p].del(Dp[u][lyr[p]]);
tmp = Nd[p].top();
if(Tp[p] != tmp) {
if(Tp[p] != -inf) {Ans[fp].del(Tp[p]);}
if(tmp != -inf) {Ans[fp].push(tmp);}
Tp[p] = tmp;
}
as = Ans[fp].Qms();
if(Ap[fp] != as)
All.push(as), All.del(Ap[fp]), Ap[fp] = as;
p = fa[p], fp = fa[p];
}
}
char s[3];
int n, m, u, v, w, root;
int main() {
mx[0] = inf;
scanf("%d", &n);
for(register int i = 1; i < n; ++i)
scanf("%d%d%d", &u, &v, &w), adde(u, v, w), adde(v, u, w);
G = 0, FG(1, 0, G, n), root = G;
solve(G, 1, 0, 0);
scanf("%d", &m);
for(register int i = 1; i <= m; ++i) {
scanf("%s", s);
if(s[0] == 'A')
if(tot != n) printf("%d\n", All.top());
else printf("They have disappeared.\n");
else scanf("%d", &u), CG(u);
}
return 0;
}
rockdu
没有帐号? 立即注册