正题
luogu 2173
题目大意
给你一个图,每条边有有一种颜色(numcolor⩽10num_{color}\leqslant 10numcolor⩽10),保证以下性质:
1.一个点连出的同色边数不大于2
2.不存在同色边组成的环
现在让你进行3钟操作:
1.修改一个点的权值
2.把两个点的连边换色(如果不存在这条边,或修改后违背上文的性质,那么不修改)
3.输出某一颜色中,一条路径上的最大值
解题思路
如果只有单颜色,那么可以用LCT维护一棵树,所有操作都可以在LCT上进行
因为numcolor⩽10num_{color}\leqslant 10numcolor⩽10,所以多颜色建多几棵LCT即可
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 10100
using namespace std;
int n, m, q, x, y, z, p, cn;
struct LCT
{int v[N], s[N], p[N], fa[N], deg[N], son[N][2];#define ls son[x][0]#define rs son[x][1]bool NR(int x){return fa[x] && (son[fa[x]][0] == x || son[fa[x]][1] == x);}bool IRS(int x){return son[fa[x]][1] == x;}void push_up(int x){s[x] = max(v[x], max(s[ls], s[rs]));return;}void pushr(int x){swap(ls, rs);p[x] ^= 1;return;}void push_down(int x){if (p[x]){if (ls) pushr(ls);if (rs) pushr(rs);p[x] = 0;}return;}void push_hall(int x){if (NR(x)) push_hall(fa[x]);push_down(x);return;}void rotate(int x){int y = fa[x], z = fa[y], k = IRS(x), g = son[x][!k];if (NR(y)) son[z][IRS(y)] = x;if (g) fa[g] = y;fa[x] = z;fa[y] = x;son[x][!k] = y;son[y][k] = g;push_up(y);return;}void Splay(int x){push_hall(x);while(NR(x)){if (NR(fa[x])){if (IRS(x) == IRS(fa[x])) rotate(fa[x]);else rotate(x);}rotate(x);}push_up(x);return;}void access(int x){for (int y = 0; x; y = x, x = fa[x])Splay(x), rs = y, push_up(x);}void make_root(int x){access(x);Splay(x);pushr(x);return;}int find_root(int x){access(x);Splay(x);while(ls) push_down(x), x = ls;Splay(x);return x;}void Split(int x, int y){make_root(x);access(y);Splay(y);return;}void link(int x, int y){deg[x]++;deg[y]++;make_root(x);if (find_root(y) != x) fa[x] = y;return;}bool cut(int x, int y){make_root(x);if (find_root(y) == x && fa[y] == x && !son[y][0]){deg[x]--;deg[y]--;fa[y] = son[x][1] = 0;push_up(x);return true;}return false;}
}T[15];//建多棵树
int main()
{scanf("%d%d%d%d", &n, &m, &cn, &q);for (int i = 1; i <= n; ++i){scanf("%d", &T[0].v[i]);for (int j = 1; j < cn; ++j)T[j].v[i] = T[0].v[i];}for (int i = 1; i <= m; ++i){scanf("%d%d%d", &x, &y, &z);T[z].link(x, y);}while(q--){scanf("%d", &x);if (x == 0){scanf("%d%d", &x, &y);for (int i = 0; i <= cn; ++i)//每种颜色的树都要修改{T[i].Splay(x);T[i].v[x] = y;T[i].push_up(x);}}else if (x == 1){scanf("%d%d%d", &x, &y, &z);p = -1;for (int i = 0; i < cn; ++i){if (T[i].cut(x, y))//看是否有这样一条边,如果有就先割掉{p = i;break;}}if (p == -1)//没有连边{puts("No such edge.");continue;}if (T[z].deg[x] == 2 || T[z].deg[y] == 2)//超度数{T[p].link(x, y);//连回去puts("Error 1.");continue;}T[z].make_root(x);if (T[z].find_root(y) == x)//已经连通了,再连就会产生环{T[p].link(x, y);puts("Error 2.");continue;}T[z].link(x, y);puts("Success.");}else if (x == 2){scanf("%d%d%d", &z, &x, &y);T[z].make_root(x);if (T[z].find_root(y) != x) puts("-1");else printf("%d\n", T[z].s[x]);}}return 0;
}