[ZJOI2012]网络(LCT)

…衆ロ難τιáo~ 提交于 2020-03-02 08:11:08

[ZJOI2012]网络(luogu)

Solution

  • 对于每个颜色建一棵 LCT
  • 由于两点间至多有一条边,可用 map 维护两点间边的颜色
  •  0 操作把每颗颜色的 LCT 上 x Splay 到 顶点,改颜色
  •  1 操作先依次判断,再断原来的边,连边
  •  2 操作在对应颜色的 LCT 内将 u 至 v 的路径提取出来,输出维护的最大值

Code

#include <cstdio>
#include <cstdlib>
#include <map>
#include <algorithm>
#define ll long long
using namespace std;
const int N=1e5+10;
int n,m,k,c,u,v,w,col[10010][11],opt;
int rev[N],ch[N][2],fa[N],val[N],ma[N],st[N];
map <ll,int> dict;
bool nroot(int x)
{
    return x==ch[fa[x]][0]||x==ch[fa[x]][1];
}
int get(int x)
{
    return x==ch[fa[x]][1];
}
void push_up(int x)
{
    ma[x]=val[x];
    if(ch[x][0]) ma[x]=max(ma[x],ma[ch[x][0]]);
    if(ch[x][1]) ma[x]=max(ma[x],ma[ch[x][1]]);
}
void change(int x)
{
    if(!x) return ;
    swap(ch[x][0],ch[x][1]);
    rev[x]^=1;
}
void push_down(int x)
{
    if(!rev[x]) return ;
    change(ch[x][0]),change(ch[x][1]);
    rev[x]=0;
}
void rotate(int x)
{
    int y=fa[x],z=fa[y],wh=get(x);
    if(nroot(y)) ch[z][get(y)]=x;
    if(ch[x][!wh]) fa[ch[x][!wh]]=y;
    ch[y][wh]=ch[x][!wh];
    ch[x][!wh]=y;
    fa[y]=x,fa[x]=z;
    push_up(y),push_up(x);
}
void splay(int x)
{
    st[++st[0]]=x;
    for(int i=x;nroot(i);i=fa[i]) st[++st[0]]=fa[i];
    for(;st[0];st[0]--) push_down(st[st[0]]);
    for(int fx;fx=fa[x],nroot(x);rotate(x))
        if(nroot(fx)) rotate(get(x)==get(fx)?fx:x);
}
void access(int x)
{
    for(int y=0;x;x=fa[y=x])
        splay(x),ch[x][1]=y,push_up(x);
}
void makeroot(int x)
{
    access(x);
    splay(x);
    change(x);
}
int findroot(int x)
{
    access(x);
    splay(x);
    while(ch[x][0]) push_down(x),x=ch[x][0];
    splay(x);
    return x;
}
int link(int x,int y)
{
    makeroot(x);
    if(findroot(y)!=x) fa[x]=y;
    else return 0;
    return 1;
}
void cut(int x,int y)
{
    makeroot(x);
    if(findroot(y)==x && fa[y]==x && !ch[y][0])
        fa[y]=ch[x][1]=0;
}
int split(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
    return y;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&c,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&val[i]);
        for(int j=1;j<c;j++) val[j*n+i]=val[i];
    }
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        w++;
        if(u>v) swap(u,v);
        col[u][w]++,col[v][w]++;
        link((w-1)*n+u,(w-1)*n+v);
        ll x=u;
        x*=n,x+=v;
        dict[x]=w;
    }
    while(k--)
    {
        scanf("%d%d%d",&opt,&u,&v);
        if(!opt)
        {
            for(int i=0;i<c;i++)
            {
                int x=i*n+u;
                splay(x),val[x]=v,push_up(x);
            }
            continue;
        }
        scanf("%d",&w);
        if(opt==1)
        {
            w++;
            if(u>v) swap(u,v);
            ll x=u;
            x*=n,x+=v;
            if(!dict.count(x))
            {
                puts("No such edge.");
                continue;
            }
            if(dict[x]==w)
            {
                puts("Success.");
                continue; 
            }
            if(col[u][w]>1 || col[v][w]>1)
            {
                puts("Error 1.");
                continue;
            }
            if(link(u+n*(w-1),v+n*(w-1))) col[u][w]++,col[v][w]++;
            else
            {
                puts("Error 2.");
                continue;
            }
            int pre=dict[x];
            cut(u+n*(pre-1),v+n*(pre-1));
            col[u][pre]--,col[v][pre]--;
            dict[x]=w;
            puts("Success.");
        }
        else
        {
            u++;
            int x=v+n*(u-1),y=w+n*(u-1);
            makeroot(x);
            if(findroot(y)!=x) puts("-1");
            else printf("%d\n",ma[split(x,y)]);
        }
    }
    return 0;
}

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!