有一个无向图G,每个点有个权值,每条边有一个颜色。这个无向图满足以下两个条件:
对于任意节点连出去的边中,相同颜色的边不超过两条。
图中不存在同色的环,同色的环指相同颜色的边构成的环。
在这个图上,你要支持以下三种操作:
修改一个节点的权值。
修改一条边的颜色。
查询由颜色c的边构成的图中,所有可能在节点u到节点v之间的简单路径上的节点的权值的最大值。
输入文件network.in的第一行包含四个正整数N, M, C, K,其中N为节点个数,M为边数,C为边的颜色数,K为操作数。
接下来N行,每行一个正整数vi,为节点i的权值。
之后M行,每行三个正整数u, v, w,为一条连接节点u和节点v的边,颜色为w。满足1 ≤ u, v ≤ N,0 ≤ w < C,保证u ≠ v,且任意两个节点之间最多存在一条边(无论颜色)。
最后K行,每行表示一个操作。每行的第一个整数k表示操作类型。
k = 0为修改节点权值操作,之后两个正整数x和y,表示将节点x的权值vx修改为y。
k = 1为修改边的颜色操作,之后三个正整数u, v和w,表示将连接节点u和节点v的边的颜色修改为颜色w。满足0 ≤ w < C。
k = 2为查询操作,之后三个正整数c, u和v,表示查询所有可能在节点u到节点v之间的由颜色c构成的简单路径上的节点的权值的最大值。如果不存在u和v之间不存在由颜色c构成的路径,那么输出“-1”。
输出文件network.out包含若干行,每行输出一个对应的信息。
对于修改节点权值操作,不需要输出信息。
对于修改边的颜色操作,按以下几类输出:
a) 若不存在连接节点u和节点v的边,输出“No such edge.”。
b) 若修改后不满足条件1,不修改边的颜色,并输出“Error 1.”。
c) 若修改后不满足条件2,不修改边的颜色,并输出“Error 2.”。
d) 其他情况,成功修改边的颜色,并输出“Success.”。
输出满足条件的第一条信息即可,即若同时满足b和c,则只需要输出“Error 1.”。
对于查询操作,直接输出一个整数。
4 5 2 7
1
2
3
4
1 2 0
1 3 1
2 3 0
2 4 1
3 4 0
2 0 1 4
1 1 2 1
1 4 3 1
2 0 1 4
1 2 3 1
0 2 5
2 1 1 4
4
Success.
Error 2.
-1
Error 1.
5
说明
颜色0为实线的边,颜色1为虚线的边,
由颜色0构成的从节点1到节点4的路径有1 – 2 – 4,故max{v1, v2, v4} = max{ 1, 2, 4 } = 4。
将连接节点1和节点2的边修改为颜色1,修改成功,输出“Success.”
将连接节点4和节点3的边修改为颜色1,由于修改后会使得存在由颜色1构成的环( 1 – 2 – 4 – 3 – 1 ),不满足条件2,故不修改,并输出“Error 2”。
不存在颜色0构成的从节点1到节点4的边,输出“-1”。
将连接节点2和节点3的边修改为颜色1,由于修改后节点2的连出去的颜色为1的边有3条,故不满足条件1,故不修改,并输出“Error 1.”。
将节点2的权值修改为5。
由颜色1构成的从节点1到节点4的路径有 1 – 2 – 4,故max{v1, v2, v4} = max{ 1, 5, 4 } = 5。
【数据规模】
对于30%的数据:N ≤ 1000,M ≤ 10000,C ≤ 10,K ≤ 1000。
另有20%的数据:N ≤ 10000,M ≤ 100000,C = 1,K ≤ 100000。
对于100%的数据:N ≤ 10000,M ≤ 100000,C ≤ 10,K ≤ 100000。
还是比较裸的LCT了, 只不过要维护10棵LCT, 多带一维数组, 打起来不顺手… 还有就是注意抛出错误的优先级…
代码如下:
#include
#include
#include
#include
#include
#include
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100005
#define ls tree[cur][now].son[0]
#define rs tree[cur][now].son[1]
#define dad tree[cur][now].fat
#define it tree[cur][now]
template <class T>
IN void in (T &x)
{
x = 0; R char c = gc;
W (!isdigit(c)) c = gc;
W (isdigit(c))
{x = (x << 1) + (x << 3) + c - 48, c = gc;}
}
namespace LCT
{
struct Node
{
int son[2], fat, val, mx, num;
bool rev;
}tree[10][MX];
int top, st[MX], dot, line, q, col;
IN bool nroot(const int &cur, const int &now)
{return tree[cur][dad].son[1] == now || tree[cur][dad].son[0] == now;}
IN bool get(const int &cur, const int &now)
{return tree[cur][dad].son[1] == now;}
IN void pushrev(const int &cur, const int &now)
{
std::swap(ls, rs);
it.rev ^= 1;
}
IN void pushdown(const int &cur, const int &now)
{
if(it.rev)
{
if(ls) pushrev(cur, ls);
if(rs) pushrev(cur, rs);
it.rev = false;
}
}
IN void pushup(const int &cur, const int &now)
{
it.mx = it.val;
if(ls) it.mx = std::max(tree[cur][ls].mx, it.mx);
if(rs) it.mx = std::max(tree[cur][rs].mx, it.mx);
}
IN void rotate(const int &cur, const int &now)
{
R bool dir = get(cur, now);
R int fa = dad, grand = tree[cur][dad].fat;
tree[cur][fa].son[dir] = it.son[dir ^ 1];
tree[cur][it.son[dir ^ 1]].fat = fa;
if(nroot(cur, fa)) tree[cur][grand].son[get(cur, fa)] = now;
it.fat = grand;
it.son[dir ^ 1] = fa;
tree[cur][fa].fat = now;
pushup(cur, fa);
}
IN void splay(R int cur, R int now)
{
int x = now; R int fa, grand;
st[top = 1] = x;
W (nroot(cur, now)) now = dad, st[++top] = now;
W (top) pushdown(cur, st[top--]);
now = x;
W (nroot(cur, now))
{
fa = dad, grand = tree[cur][fa].fat;
if(nroot(cur, fa)) rotate(cur, get(cur, now) == get(cur, fa) ? fa : now);
rotate(cur, now);
}
pushup(cur, now);
}
IN void access(R int cur, R int now)
{
for (R int x = 0; now; x = now, now = dad)
splay(cur, now), it.son[1] = x, pushup(cur, now);
}
IN void make_root(const int &cur, const int &now)
{access(cur, now), splay(cur, now), pushrev(cur, now);}
IN int find_root(R int cur, R int now)
{
access(cur, now), splay(cur, now);
W (ls) pushdown(cur, now), now = ls;
return now;
}
IN void split(const int &cur, const int &x, const int &y)
{make_root(cur, x), access(cur, y), splay(cur, y);}
IN bool link(const int &cur, const int &x, const int &y)
{
make_root(cur, x);
if(tree[cur][x].num == 2 || tree[cur][y].num == 2)
{
printf("Error 1.\n");
return false;
}
if(find_root(cur, y) != x)
{
tree[cur][x].fat = y, tree[cur][x].num++, tree[cur][y].num++;
return true;
}
else
{
printf("Error 2.\n");
return false;
}
}
IN void cut(const int &cur, const int &x, const int &y)
{
tree[cur][x].fat = tree[cur][y].son[0] = 0;
tree[cur][x].num--, tree[cur][y].num--;
pushup(cur, y);
}
IN void modify_dot(const int &tar, const int &del)
{
for (R int i = 0; i < col; ++i)
make_root(i, tar), tree[i][tar].val = del, pushup(i, tar);
}
IN void modify_edge(const int &from, const int &to, const int &del)
{
for (R int i = 0; i < col; ++i)
{
make_root(i, from);
if(find_root(i, to) == from && tree[i][from].fat == to && !tree[i][from].son[1])
{
cut(i, from, to);
if(link(del, from, to))
{
printf("Success.\n");
return;
}
else
{
link(i, from, to);
return;
}
}
}
printf("No such edge.\n");
}
IN void query(const int &cur, const int &from, const int &to)
{
make_root(cur, from);
if(find_root(cur, to) != from)
{ printf("-1\n"); return;}
split(cur, from, to);
printf("%d\n", tree[cur][to].mx);
}
}
using namespace LCT;
int main(void)
{
R int a;
int b, c, d;
in(dot), in(line), in(col), in(q);
for (R int i = 1; i <= dot; ++i)
{
in(a);
for (R int j = 0; j < col; ++j) tree[j][i].val = tree[j][i].mx = a;
}
for (R int i = 1; i <= line; ++i)
{
in(a), in(b), in(c);
make_root(c, a);
make_root(c, b);
tree[c][a].num++, tree[c][b].num++;
tree[c][a].fat = b;
}
W (q--)
{
in(a);
switch(a)
{
case 0:
{
in(b), in(c);
modify_dot(b, c);
break;
}
case 1:
{
in(b), in(c), in(d);
modify_edge(b, c, d);
break;
}
case 2:
{
in(b), in(c), in(d);
query(b, c, d);
break;
}
}
}
}