题意:
给出一个无向图,每条边都有一种颜色,每个点都有一个点权。
要求支持修改点权,修改边的颜色,以及询问两点之间以某个颜色连接的路径上的点权最大值。
保证不会出现同色边构成的环,每个节点都至多有两条某个颜色的路径和它相连。
思路:
每种颜色的边构成了若干条链,直接用splay维护序列点权最大值。
修改边的颜色其实就是分裂和合并操作,只是合并时需要对树的形态进行讨论,可能需要记反转标记。
另外询问时需要特判u = v的情况,因为这个卡了4个小时。。。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
#include <cstring>
#include <cstdlib>
#define For(i,j,k) for(int i = j;i <= k;i++)
#define Forr(i,j,k) for(int i = j;i >= k;i--)
#define Set(i,j) memset(i, j, sizeof(i))
using namespace std;
const int N = 10010, C = 12;
int n, m, q, c;
struct Splay{
int ch[N][2], Max[N], val[N], fa[N], rev[N], deg[N];
void maintain(int u){
Max[u] = val[u];
if(ch[u][0]) Max[u] = max(Max[u], Max[ch[u][0]]);
if(ch[u][1]) Max[u] = max(Max[u], Max[ch[u][1]]);
}
void pushdown(int u){
if(rev[u]){
if(ch[u][0]) rev[ch[u][0]] ^= 1;
if(ch[u][1]) rev[ch[u][1]] ^= 1;
rev[u] = 0;
swap(ch[u][0], ch[u][1]);
}
}
void rotate(int u){
int v = fa[u], f = fa[v], x = (ch[v][1] == u);
fa[u] = f;
if(f) ch[f][ch[f][1] == v] = u;
ch[v][x] = ch[u][x ^ 1], fa[ch[v][x]] = v;
ch[u][x ^ 1] = v, fa[v] = u;
maintain(v), maintain(u);
}
void push(int h){
if(fa[h]) push(fa[h]);
pushdown(h);
}
void splay(int v, int u){
push(v);
while(fa[v] != u){
if(fa[fa[v]] != u) rotate(fa[v]);
rotate(v);
}
}
int root(int u){
while(fa[u]) u = fa[u];
return u;
}
void cut(int u, int v){
splay(u, 0), splay(v, u);
ch[u][ch[u][1] == v] = 0, fa[v] = 0;
deg[v]--, deg[u]--;
maintain(u);
}
bool link(int u, int v, bool out = true){
if(deg[u] >= 2 || deg[v] >= 2){
puts("Error 1."); return false;
}
if(root(v) == root(u)){
puts("Error 2."); return false;
}
deg[u]++, deg[v]++;
splay(u, 0), splay(v, 0);
if(ch[u][1]) rev[u] ^= 1, pushdown(u);
if(ch[v][0]) rev[v] ^= 1, pushdown(v);
fa[u] = v, ch[v][0] = u;
maintain(u);
if(out) puts("Success.");
return true;
}
void update(int u, int v){
splay(u, 0);
val[u] = v;
maintain(u);
}
int query(int u, int v){
if(root(u) != root(v)) return -1;
if(u == v) return val[u];
splay(u, 0), splay(v, u);
return max(Max[ch[v][ch[u][0] == v]], max(val[u], val[v]));
}
}Tree[C];
map<int, int> M[N];
int main(){
scanf("%d%d%d%d", &n, &m, &c, &q);
For(i,1,n){
scanf("%d", &Tree[0].val[i]);
For(j,0,c-1) Tree[j].val[i] = Tree[j].Max[i] = Tree[0].val[i];
}
For(i,1,m){
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
M[x][y] = w, M[y][x] = w;
Tree[w].link(x, y, false);
}
while(q--){
int k, x, y, z;
scanf("%d%d%d", &k, &x, &y);
if(!k) For(i,0,c-1) Tree[i].update(x, y);
else if(k == 1){
scanf("%d", &z);
if(!M[x].count(y)) puts("No such edge.");
else{
Tree[M[x][y]].cut(x, y);
if(!Tree[z].link(x, y)) Tree[M[x][y]].link(x, y, 0);
else M[x][y] = M[y][x] = z;
}
}
else{
scanf("%d", &z);
printf("%d\n", Tree[x].query(y, z));
}
}
return 0;
}