【bzoj2816】[ZJOI2012]网络 LCT

题目描述 Description

有一个无向图G,每个点有个权值,每条边有一个颜色。这个无向图满足以下两个条件:
1. 对于任意节点连出去的边中,相同颜色的边不超过两条。
2. 图中不存在同色的环,同色的环指相同颜色的边构成的环。
在这个图上,你要支持以下三种操作:
0. 修改一个节点的权值。
1. 修改一条边的颜色。
2. 查询由颜色c的边构成的图中,所有可能在节点u到节点v之间的简单路径上的节点的权值的最大值。

输入描述 Input Description

第一行包含四个正整数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表示操作类型。
0. k = 0为修改节点权值操作,之后两个正整数x和y,表示将节点x的权值vx修改为y。
1. k = 1为修改边的颜色操作,之后三个正整数u, v和w,表示将连接节点u和节点v的边的颜色修改为颜色w。满足0 ≤ w < C。
2. k = 2为查询操作,之后三个正整数c, u和v,表示查询所有可能在节点u到节点v之间的由颜色c构成的简单路径上的节点的权值的最大值。如果不存在u和v之间不存在由颜色c构成的路径,那么输出“-1”。

输出描述 Output Description

包含若干行,每行输出一个对应的信息。
1. 对于修改节点权值操作,不需要输出信息。
2. 对于修改边的颜色操作,按以下几类输出:
a) 若不存在连接节点u和节点v的边,输出“No such edge.”。
b) 若修改后不满足条件1,不修改边的颜色,并输出“Error 1.”。
c) 若修改后不满足条件2,不修改边的颜色,并输出“Error 2.”。
d) 其他情况,成功修改边的颜色,并输出“Success.”。
输出满足条件的第一条信息即可,即若同时满足b和c,则只需要输出“Error 1.”。
3. 对于查询操作,直接输出一个整数。 第 5

样例输入 Sample Input

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

样例输出 Sample Output

4
Success.
Error 2.
-1
Error 1.
5

数据范围及提示 Data Size & Hint

【数据规模】
对于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。


题面是codevs的

我傻X,我不会写LCT

判断两点是否直接有边的姿势

顺便一说 3651和这题一样

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int INF = 1000000010;
const int SZ = 100010;

struct node{
    node *ch[2],*f;
    int v,maxn,sz;
    bool rev;

    void maintain()
    {
        maxn = max(v,max(ch[0] -> maxn,ch[1] -> maxn));
        sz = ch[0] -> sz + 1 + ch[1] -> sz;
    }

    void pushdown();

    void setc(node *x,int d) { (ch[d] = x) -> f = this; }

    bool isroot() { return f -> ch[0] != this && f -> ch[1] != this; }

    int dir() { return f -> ch[1] == this; }

}T[2000010],*rt[SZ][20],*null;

int Tcnt = 0;

node* newnode(int x)
{
    node *k = T + (Tcnt ++);
    k -> f = k -> ch[0] = k -> ch[1] = null;
    k -> v = k -> maxn = x;
    k -> rev = 0;
    return k;
}

void rotate(node *p)
{
    int d = p -> dir();
    node *fa = p -> f;
    p -> f = fa -> f;
    if(!fa -> isroot()) 
        p -> f -> ch[fa -> dir()] = p;
    fa -> ch[d] = p -> ch[d ^ 1];
    if(fa -> ch[d] != null)
        fa -> ch[d] -> f = fa;
    p -> setc(fa,d ^ 1);
    fa -> maintain(); p -> maintain();
}

void pushrev(node *p)
{
    if(p == null) return;
    swap(p -> ch[0],p -> ch[1]);
    p -> rev ^= 1;
}

void node :: pushdown()
{
    if(rev)
    {
        pushrev(ch[0]); pushrev(ch[1]);
        rev = 0;
    }
}

node* S[SZ];

void pushpath(node *p)
{
    int top = 0;
    while(!p -> isroot()) S[++ top] = p,p = p -> f;
    S[++ top] = p;
    while(top) S[top --] -> pushdown();
}

void splay(node *p)
{
    pushpath(p);
    while(!p -> isroot())
    {
        if(p -> f -> isroot()) rotate(p);
        else
        {
            if(p -> f -> dir() == p -> dir()) rotate(p -> f),rotate(p);
            else rotate(p),rotate(p);
        }
    }
    p -> maintain();
}

void access(node *p)
{
    node *last = null;
    while(p != null)
    {
        splay(p);
        p -> ch[1] = last; p -> maintain();
        last = p;
        p = p -> f;
    }
}

void makeroot(node *p)
{
    access(p); splay(p); pushrev(p);
}

int ask_max(node *u,node *v)
{
    makeroot(u); access(v); splay(v);
    return v -> maxn;
}

void change(node *p,int x)
{
    access(p); splay(p); p -> v = x; 
    p -> maintain();
}

node* find_rt(node *p)
{
    while(p -> f != null) p = p -> f;
    return p;
}

void cut(node *u,node *v)
{
    makeroot(u); access(v); splay(v);
    v -> ch[0] = u -> f = null; v -> maintain();
}

void link(node *u,node *v)
{
    makeroot(u); u -> f = v;
}

bool check(node *u,node *v)
{
    makeroot(u); access(v); splay(v);
    return v -> sz == 2;
}


int Du[SZ][20];

int val[SZ];

void init(int n,int c)
{
    null = newnode(-INF);
    for(int i = 1;i <= n;i ++)
        for(int j = 0;j < c;j ++)
            rt[i][j] = newnode(val[i]);
}

int main()
{
    int n,m,c,t;
    scanf("%d%d%d%d",&n,&m,&c,&t);
    for(int i = 1;i <= n;i ++)
        scanf("%d",&val[i]);
    init(n,c);
    for(int i = 1;i <= m;i ++)
    {
        int u,v,k;
        scanf("%d%d%d",&u,&v,&k);
        link(rt[u][k],rt[v][k]);
        Du[u][k] ++; Du[v][k] ++;
    }
    while(t --)
    {
        int opt;
        scanf("%d",&opt);
        if(opt == 0)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            val[x] = y;
            for(int i = 0;i < c;i ++)
                change(rt[x][i],y);
        }
        else if(opt == 1)
        {
            int u,v,k;
            scanf("%d%d%d",&u,&v,&k);
            int lastk = -1;
            for(int i = 0,first = 0;i < c;i ++)
                if(find_rt(rt[u][i]) == find_rt(rt[v][i]) && check(rt[u][i],rt[v][i])) 
                {
                    lastk = i;
                    if(++ first > 1) puts("fuck");
                    break;
                }
        //  printf("%d %d\n",k,lastk);
            if(!~lastk) puts("No such edge."); //没边 
            else if(k == lastk) puts("Success.");
            else if(Du[u][k] > 1 || Du[v][k] > 1) puts("Error 1."); //度为2 
            else if(find_rt(rt[u][k]) == find_rt(rt[v][k])) puts("Error 2."); //有环 
            else
            {
                puts("Success.");
                cut(rt[u][lastk],rt[v][lastk]);
                link(rt[u][k],rt[v][k]);
                Du[u][lastk] --; Du[v][lastk] --;
                Du[u][k] ++; Du[v][k] ++;
            }
        }
        else
        {
            int u,v,k;
            scanf("%d%d%d",&k,&u,&v);           
            if(find_rt(rt[u][k]) != find_rt(rt[v][k])) puts("-1");
            else printf("%d\n",ask_max(rt[u][k],rt[v][k]));
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值