题解:P2173 [ZJOI2012] 网络
典中典 LCT。
题目保证了 ,而又保证了图有如下性质:
对于任意节点连出去的边中,相同颜色的边不超过两条。
图中不存在同色的环,同色的环指相同颜色的边构成的环。
这事实上保证了每种颜色的图单独拎出来是一个森林。
考虑对于每种颜色维护一颗 LCT。
修改点权是平凡的,在每一颗上都直接修改即可;
查询操作直接在对应颜色的 LCT 查即可;
修改边颜色相对复杂。拿一个数组统计对应颜色的边的数量。一个 map 维护边的存在性。对于能修改的情况,就断掉原颜色上 LCT 的连接,建立新连接。注意更新那个统计数组和 map。细节看代码吧。
::::success[Code]
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+5;
struct LCT {
int ch[N][2], fa[N], val[N], maxn[N], rev[N], stk[N];
inline int get(int x) {
return ch[fa[x]][1] == x;
}
inline bool is_root(int x) {
return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
}
inline void pushup(int x) {
maxn[x] = val[x];
if (ch[x][0])
maxn[x] = max(maxn[x], maxn[ch[x][0]]);
if (ch[x][1])
maxn[x] = max(maxn[x], maxn[ch[x][1]]);
}
inline void pushdown(int x) {
if (rev[x]) {
swap(ch[x][0], ch[x][1]);
if (ch[x][0])
rev[ch[x][0]] ^= 1;
if (ch[x][1])
rev[ch[x][1]] ^= 1;
rev[x] = 0;
}
}
inline void rotate(int x) {
int y = fa[x], z = fa[y];
int k = get(x);
if (!is_root(y))
ch[z][get(y)] = x;
fa[x] = z;
ch[y][k] = ch[x][k ^ 1];
if (ch[x][k ^ 1])
fa[ch[x][k ^ 1]] = y;
ch[x][k ^ 1] = y;
fa[y] = x;
pushup(y);
pushup(x);
}
void splay(int x) {
int top = 0, cur = x;
stk[++top] = cur;
while (!is_root(cur))
cur = fa[cur], stk[++top] = cur;
while (top)
pushdown(stk[top--]);
while (!is_root(x)) {
int y = fa[x];
if (!is_root(y)) {
if (get(x) == get(y))
rotate(y);
else
rotate(x);
}
rotate(x);
}
}
void access(int x) {
for (int y = 0; x; y = x, x = fa[x]) {
splay(x);
ch[x][1] = y;
pushup(x);
}
}
void make_root(int x) {
access(x);
splay(x);
rev[x] ^= 1;
}
int find_root(int x) {
access(x);
splay(x);
pushdown(x);
while (ch[x][0])
x = ch[x][0], pushdown(x);
splay(x);
return x;
}
void link(int x, int y) {
make_root(x);
if (find_root(y) != x)
fa[x] = y;
}
void cut(int x, int y) {
make_root(x);
if (find_root(y) == x && fa[y] == x && !ch[y][0])
fa[y] = ch[x][1] = 0, pushup(x);
}
void update(int x, int k) {
splay(x);
val[x] = k;
pushup(x);
}
int query(int x, int y) {
make_root(x);
if (find_root(y) != x)
return -1;
return maxn[x];
}
} lct[11];
int cnt[11][N];
map<pair<int, int>, int> mp;
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n, m, C, k;
cin >> n >> m >> C >> k;
for (int i = 1; i <= n; i++) {
int w;
cin >> w;
for (int c = 0; c < C; c++)
lct[c].val[i] = lct[c].maxn[i] = w;
}
for (int i = 1; i <= m; i++) {
int u, v, c;
cin >> u >> v >> c;
if (u > v)
swap(u, v);
mp[ {u, v}] = c;
lct[c].link(u, v);
cnt[c][u]++;
cnt[c][v]++;
}
while (k--) {
int op;
cin >> op;
if (op == 0) {
int x, y;
cin >> x >> y;
for (int c = 0; c < C; c++) lct[c].update(x, y);
} else if (op == 1) {
int u, v, w;
cin >> u >> v >> w;
if (u > v)
swap(u, v);
if (mp.find({u, v}) == mp.end()) {
cout << "No such edge.\n";
} else {
int o = mp[ {u, v}];
if (o == w) {
cout << "Success.\n";
} else if (cnt[w][u] > 1 || cnt[w][v] > 1) {
cout << "Error 1.\n";
} else if (lct[w].find_root(u) == lct[w].find_root(v)) {
cout << "Error 2.\n";
} else {
lct[o].cut(u, v);
cnt[o][u]--;
cnt[o][v]--;
lct[w].link(u, v);
cnt[w][u]++;
cnt[w][v]++;
mp[ {u, v}] = w;
cout << "Success.\n";
}
}
} else {
int c, u, v;
cin >> c >> u >> v;
cout << lct[c].query(u, v) << '\n';
}
}
return 0;
}
::::
评论