Splay [ZJOI2012网络]

本文介绍了一种使用Splay树解决特定图问题的方法。通过维护不同颜色边所构成的子图,实现节点权值更新、边颜色更改及查询节点间路径最大权值的功能。文章详细展示了Splay树的操作细节及其在图算法中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

一个网络支持一下操作:
修改一个节点的权值。
修改一条边的颜色。
查询由颜色c的边构成的图中,所有可能在节点u到节点v之间的简单路径上的节点的权值的最大值。

做法:对于每一种颜色,用一棵Splay维护最大值即可。

注意:rotate请不要打错(grandfa的儿子要另外判断左右)。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
const int maxc=13;
const int maxn=10010;
int n,m,c,k;
struct Splay{
    int ch[maxn][2],Max[maxn],rev[maxn];
    int deg[maxn],val[maxn];
    int fa[maxn];
    int root(int x){
        while(fa[x]){
            x=fa[x];
        }
        return x;
    }
    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 rotate(int u){
        int v=fa[u];
        int l=(u==ch[v][1]);
        fa[u]=fa[v];
        if(fa[v]) ch[fa[v]][ch[fa[v]][1]==v]=u;
        ch[v][l]=ch[u][l^1];fa[ch[u][l^1]]=v;
        fa[v]=u;ch[u][l^1]=v;
        maintain(v);
        maintain(u);    
    }
    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 push(int u){
        if(fa[u]) push(fa[u]);
        pushdown(u);
    }
    void splay(int u,int v){
        push(u);
        while(fa[u]!=v){
            if(fa[fa[u]]!=v) rotate(fa[u]);
            rotate(u);
        }
    }
    bool link(int x,int y,bool out=true){
        if(deg[x]>=2 || deg[y]>=2){
            printf("Error 1.\n");return false;
        }
        if(root(x)==root(y)){
            printf("Error 2.\n");return false;
        }
        deg[x]++;deg[y]++;
        splay(x,0);splay(y,0);
        if(ch[y][0]) rev[y]^=1,pushdown(y);
        if(ch[x][1]) rev[x]^=1,pushdown(x);
        fa[x]=y;
        ch[y][0]=x;
        maintain(x);
        if(out) printf("Success.\n");
        return true;
    }
    void del(int x,int y){
        splay(x,0);splay(y,x);
        fa[y]=0;
        ch[x][y==ch[x][1]]=0;
        deg[x]--;deg[y]--;
        maintain(x);
    }
    void query(int x,int y){
        if(root(x)!=root(y)){
            printf("-1\n");return;
        }
        if(x==y){
            printf("%d\n",val[x]);return;
        }
        splay(y,0);splay(x,y);
        printf("%d\n",max(max(val[x],val[y]),Max[ch[x][x==ch[y][0]]]));
    }
    void update(int x,int y){
        splay(x,0);
        val[x]=y;
        maintain(x);
    }
}tree[maxc];
map<int,int>color[maxn];
int main(){
    freopen("txt.in","r",stdin);
    freopen("txt.out","w",stdout);
    scanf("%d%d%d%d",&n,&m,&c,&k);
    for(int i=1;i<=n;i++){
        scanf("%d",&tree[0].val[i]);
        for(int j=0;j<c;j++){
            tree[j].val[i]=tree[j].Max[i]=tree[0].val[i];
        }
    }
        for(int i=1;i<=m;i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            color[u][v]=color[v][u]=w;
            tree[w].link(u,v,0);
        }
        for(int i=1;i<=k;i++){
            int op,x,y;
            scanf("%d%d%d",&op,&x,&y);
            if(op==0){
                for(int j=0;j<c;j++) tree[j].update(x,y);
            }else if(op==1){
                int w;
                scanf("%d",&w);
                if(!color[x].count(y)) printf("No such edge.\n");
                else{
                    tree[color[x][y]].del(x,y);
                    if(!tree[w].link(x,y)) tree[color[x][y]].link(x,y,0);
                    else color[x][y]=color[y][x]=w;
                }
            }else{
                int z;
                scanf("%d",&z);
                tree[x].query(y,z);
            }
        }
    return 0;
}

^_^

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值