P2173 [ZJOI2012] 网络

P2173 [ZJOI2012] 网络

题目描述

有一个无向图 \(G\),每个点有个权值,每条边有一个颜色。这个无向图满足以下两个条件:

1、 对于任意节点连出去的边中,相同颜色的边不超过两条。

2、图中不存在同色的环,同色的环指相同颜色的边构成的环。

在这个图上,你要支持以下三种操作:

  • 0 x y 表示把节点 \(x\) 的权值改为 \(y\)

  • 1 u v w 表示将边 \((u,v)\) 的颜色改为 \(w\)

  • 2 c u v 表示查询由颜色 \(c\) 的边构成的图中,所有可能在 \(u \to v\) 之间的简单路径上的节点的权值的最大值。

输入格式

第一行四个正整数 \(n,m,C,k\),分别表示节点数、边数、颜色数和操作数。

接下来 \(n\) 行,每行一个正整数 \(v_i\),为节点 \(i\) 的权值。

之后 \(m\) 行,每行三个正整数 \(u,v,w\),为一条连接 \(u,v\) 节点的边,颜色为\(w\)

最后 \(k\) 行,每行若干个正整数,表示一次操作。

输出格式

输出若干行,每行输出一个对应的信息。

1、 对于修改节点权值操作,不需要输出信息。

2、对于修改边的颜色操作,按以下几类输出:

  • 若不存在连接节点 \(u\) 和节点 \(v\) 的边,输出 No such edge.

  • 若修改后不满足条件 \(1\),不修改边的颜色,并输出 Error 1.

  • 若修改后不满足条件 \(2\),不修改边的颜色,并输出 Error 2.

  • 其他情况,成功修改边的颜色,并输出 Success.

输出满足条件的第一条信息即可,即若同时不满足条件 \(1,2\) ,则只需要输出Error 1.

3、 对于查询操作,输出一个整数表示答案。若 \(u,v\) 之间没有颜色 \(c\) 构成的路径,则输出 \(-1\)

【数据范围】

对于 \(100\%\) 的数据:\(n ≤ 10^4\)\(m ≤ 10^5\)\(C ≤ 10\)\(k ≤ 10^5\)

\(1\le u,v,x \le n\)\(0 \le c < C\),保证图中没有重边和自环。

说句闲话

终于写到 LCT 了,我自己都没想到我居然欠了这么多解题报告没写,感觉今天补不完啊 QAQ.

Solution:

首先我们狠狠阅读一下题目:
1、 对于任意节点连出去的边中,相同颜色的边不超过两条。

2、图中不存在同色的环,同色的环指相同颜色的边构成的环。

\(C ≤ 10\)

这启示我们针对每个颜色建一颗 LCT.然后就很板子了:

操作1我们就直接改颜色,操作二在经过一系列判断之后把原颜色的 LCT 上的边删掉,然后在新的颜色的 LCT 上加边,操作3直接 splite 就行。

操作2的“一系列操作”详见代码。

Code:

#include<bits/stdc++.h>
const int N=1e5+5;
const int C=10;
using namespace std;
int st[N];
int Max(int x,int y){return x>y ? x : y;}
int w[N];
struct LCT{
    struct Tree{
        int mx,val,tag,ff,ch[2];
    }t[N<<2];
    #define ls t[x].ch[0]
    #define rs t[x].ch[1]
    #define fa t[x].ff
    inline bool isroot(int x)
    {
        return (t[fa].ch[0]==x||t[fa].ch[1]==x);
    }
    inline void pushup(int x)
    {
        t[x].mx=Max(Max(t[ls].mx,t[rs].mx),t[x].val);
        return;
    }
    inline void rev(int x)
    {
        swap(t[x].ch[0],t[x].ch[1]);
        t[x].tag^=1;
        return ;
    }
    inline void pushdown(int x)
    {
        if(t[x].tag)
        {
            if(ls)rev(ls);
            if(rs)rev(rs);
            t[x].tag=0;
        }
        return ;
    }
    inline void rotate(int x)
    {
        int y=fa,z=t[fa].ff,k=t[fa].ch[1]==x ? 1 : 0;
        if(isroot(y))t[z].ch[t[z].ch[1]==y]=x;
        t[x].ff=z;

        t[y].ch[k]=t[x].ch[!k];
        if(t[x].ch[!k])t[t[x].ch[!k]].ff=y;

        t[x].ch[!k]=y;
        t[y].ff=x;
        pushup(y);
    }
    inline void splay(int x)
    {
        int y=x,z=0;
        st[++st[0]]=y;
        while(isroot(y))st[++st[0]]=y=t[y].ff;
        while(st[0])pushdown(st[st[0]--]);
        while(isroot(x)&&x)//isn't root
        {
            y=fa,z=t[fa].ff;
            if(isroot(y)){rotate((t[y].ch[1]==x)==(t[z].ch[1]==y) ? y : x);}
            rotate(x);
        }
        pushup(x);
    }
    void access(int x)
    {
        int y=0;
        while(x)
        {
            splay(x);rs=y;pushup(x);
            y=x;x=fa;
        }
    }
    void make_root(int x)//换根
    {
        access(x);splay(x);
        rev(x);
    }
    int find(int x)
    {
        access(x);splay(x);
        while(ls)pushdown(x),x=ls;
        splay(x);
        return x;
    }
    bool splite(int x,int y)
    {
        make_root(x);
        if(find(y)!=x)return 0;
        access(y);splay(y);
        return 1;
    }
    bool link(int x,int y)// 意义很明确的函数名称
    {
        make_root(x);
        if(find(y)!=x){t[x].ff=y;return 1;}
        return 0;
    }
    bool cut(int x,int y)// 意义很明确的函数名称
    {
        make_root(x);
        if(find(y)==x&&t[y].ff==x&&t[y].ch[0]==0)
        {
            t[y].ff=t[x].ch[1]=0;
            pushup(x);
            return 1;
        }        return 0;
    }
}T[C];
int d[C][N];
int n,m,p,q;
map<pair<int,int>,int> Map;
#define mp(x,y) make_pair(x,y)
void work()
{
    cin>>n>>m>>p>>q;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&w[i]);
    }
    for(int j=0;j<p;j++)for(int i=1;i<=n;i++)T[j].t[i].val=T[j].t[i].mx=w[i];
    for(int i=1,x,y,col;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&col);
        T[col].link(x,y);d[col][x]++;d[col][y]++;
        Map[mp(x,y)]=col+1;
        Map[mp(y,x)]=col+1;
    }
    int opt,x,y,z;
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d%d",&opt,&x,&y);
        if(opt==0)
        {
            w[x]=y;
            for(int j=0;j<p;j++)
            {
                T[j].t[x].val=w[x];
                T[j].splay(x);
            }
            continue;
        }
        scanf("%d",&z);
        if(opt==1)
        {
            if(z==Map[mp(x,y)]-1){printf("Success.\n");continue;}
            if(!Map[mp(x,y)]){printf("No such edge.\n");continue;}
            if(d[z][x]==2||d[z][y]==2){printf("Error 1.\n");continue;}
            if(T[z].link(x,y))
            {
                int col=Map[mp(x,y)]-1;Map[mp(x,y)]=Map[mp(y,x)]=z+1;
                T[col].cut(x,y);
                d[col][x]--,d[col][y]--;
                d[z][x]++,d[z][y]++;
                printf("Success.\n");
            }
            else {printf("Error 2.\n");}
        }
        if(opt==2)
        {
            if(T[x].splite(y,z))
            {
                printf("%d\n",Max(T[x].t[z].mx,T[x].t[z].val));
            }
            else
            {
                printf("%d\n",-1);
            }
        }
    }
}
int main()
{
    //freopen("network.in","r",stdin);
    //freopen("network.out","w",stdout);
    work();
    return 0;
}
posted @ 2025-01-24 16:22  liuboom  阅读(9)  评论(0)    收藏  举报