ZJOI2012 network splay

题意:

给出一个无向图,每条边都有一种颜色,每个点都有一个点权。

要求支持修改点权,修改边的颜色,以及询问两点之间以某个颜色连接的路径上的点权最大值。

保证不会出现同色边构成的环,每个节点都至多有两条某个颜色的路径和它相连。


思路:

每种颜色的边构成了若干条链,直接用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;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值