[Luogu P2173] [ZJOI2012]网络

洛谷传送门

题目描述

有一个无向图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.”。

对于查询操作,直接输出一个整数。

输入输出样例
输入样例#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

输出样例#1:

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 <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#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;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值