- https://codeforces.com/contest/1787
- TypeDB Forces 2023 (Div. 1 + Div. 2) C (dp) D(dfs), 严格鸽
- TypeDB Forces 2023 (Div. 1 + Div. 2, Rated, Prizes!), Immortality
Problem G. Colorful Tree Again
题意:给定一个边权图,初始固定每个边有颜色和边权。每个节点也有颜色,初始都是黑色。
每次操作可以改变一个节点的颜色,并询问当前最大的好的路径的权值和是多少。
一个路径是好的,当且仅当路径上的所有点颜色相同,并包含了所有该颜色的边,且路径上经过的所有节点的颜色为白。
解法:这个题首先第一反应是 QTREE 4 和 QTREE 6 的某种结合。。。 但是仔细读题发现判定的条件是 path 而不是 component !!!
因而题目难度大幅简化。。。但是想写得简洁依然会很困难。。。
首先第一步当然是剔除不合法的颜色。。。(最好用度数做简单的判定,不要在 dfs() 的时候判定。。)
然后再 dfs() 的时候,剩下的路径都有且仅有一个最高点。。我们对所有最高点位 u 的路径都放在一个堆里维护,记做 Q[u]…
那么在用所有的 Q[u] 组织一个堆来维护最优解。。(类似动态直径问题的点分树做法里最有的堆。。。)
那么每次 toggle 一个点时,除了会影响 Q[u].. 还会影响 u 向上的一条路径。。
记录那条路径所在的堆为 Q[y],那么如果现在 Q[y] 包含在 ans 里时,更新 Q[y] 前后还要顺手更新一下 ans。
无论那种情况,我们现在都可以 O(1) 的 push()、pop() 操作进行处理。。
那么我们只需要实现一个可删除堆即可。。。stl 里的堆自然是不可定向删除的。。。
所以现在主流的 Dijkstra 模板里要求可删除堆的时候。。其实我们都是做延迟处理。。(尽管 clrs 里其实有可删除堆的相关代码。)
这里我们也可以用类似的方法。。。
对于每个堆,再开一个辅助堆,记录删除过的值即可。。
#include <lastweapon/io>
using namespace lastweapon;
const int N = int(2e5) + 9;
struct heap {
priority_queue<LL>Q, q;
void push(LL x){if(x)Q.push(x);}
void pop(LL x){if(x)q.push(x);}
LL top() {
while(!q.empty() && Q.top() == q.top()) Q.pop(), q.pop();
if (Q.empty()) return 0;
return Q.top();
}
};
vector<pair<int, PII>> adj[N]; map<int, int> sub[N]; heap Q[N], ans;
LL W[N]; bool path[N], bad[N]; int top[N], upc[N], del[N];
// 颜色的权值和,该颜色是否组成路径,节点是否已损坏,颜色的最高代表点,点到父亲的边的颜色,除最高点外路径被阻塞的次数
int n;
void dfs(int u = 1, int p = 0) {
for (auto e: adj[u]) {
int v = e.fi; if (v == p) continue;
int w = e.se.fi, c = e.se.se;
if (!top[c]) top[c] = u;
upc[v] = c; dfs(v, u);
}
}
void fix(int x) {
if (bad[x]) {
ans.pop(Q[x].top());
if (x != 1) {
int c = upc[x]; if (!path[c]) return;
if (del[c]++) return;
int y = top[c];
if (!bad[y]) ans.pop(Q[y].top());
Q[y].pop(W[c]);
if (!bad[y]) ans.push(Q[y].top());
}
} else {
ans.push(Q[x].top());
if (x != 1) {
int c = upc[x]; if (!path[c]) return;
if (--del[c]) return;
int y = top[c];
if (!bad[y]) ans.pop(Q[y].top());
Q[y].push(W[c]);
if (!bad[y]) ans.push(Q[y].top());
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int q; RD(n, q); DO(n-1) {
int x, y, w, c; RD(x, y, w, c); ++sub[c][x]; ++sub[c][y]; W[c] += w;
adj[x].PB({y, {w, c}}); adj[y].PB({x, {w, c}});
}
dfs();
REP_1(c, n) if (W[c]) {
int c1 = 0; path[c] = 1;
for (auto e: sub[c]) {
if (e.se == 1) ++c1;
else if (e.se != 2) {
path[c] = 0;
break;
}
}
path[c] &= c1 == 2;
if (path[c]) Q[top[c]].push(W[c]);
}
REP_1(i, n) ans.push(Q[i].top());
DO(q) {
int p, x; RD(p, x); bad[x] = !p; fix(x);
printf("%lld\n", ans.top());
}
}




Alca
Amber
Belleve Invis
Chensiting123
Edward_mj
Fotile96
Hlworld
Kuangbin
Liyaos
Lwins
LYPenny
Mato 完整版
Mikeni2006
Mzry
Nagatsuki
Neko13
Oneplus
Rukata
Seter
Sevenkplus
Sevenzero
Shirleycrow
Vfleaking
wangzhpp
Watashi
WJMZBMR
Wywcgs
XadillaX
Yangzhe
三途川玉子
About.me
Vijos
