[BZOJ3651]网络通信(LCT)

题目:

我是超链接

题解:

1A辣!!!!
给每个公司建一棵树,就是给每个数组多一维id呗,辅助树转来转去也是在id层面上转
看了看发现这个题要迅速找到某条边对应的管辖公司,给每条边一个id,简单一点就是。。(x-1)*8000+y
那看起来挺大的啊,map走起!

代码:

#include <map>
#include <cstdio>
#include <iostream>
using namespace std;
const int N=8005;const int C=105;
int ch[C][N][2],f[C][N],stack[N],du[C][N],deltaz[C][N];
map<int,int> mp;
int get(int id,int x){return ch[id][f[id][x]][1]==x;}
bool Is_root(int id,int x){return ch[id][f[id][x]][0]!=x && ch[id][f[id][x]][1]!=x;}
void pushdown(int id,int x)
{
    if (deltaz[id][x])
    {
        swap(ch[id][x][0],ch[id][x][1]);
        deltaz[id][ch[id][x][0]]^=1; deltaz[id][ch[id][x][1]]^=1;
        deltaz[id][x]=0;
    }
}
void rotate(int id,int x)
{
    int old=f[id][x],oldf=f[id][old],which=get(id,x);bool gen=Is_root(id,old);
    ch[id][old][which]=ch[id][x][which^1]; f[id][ch[id][x][which^1]]=old;
    ch[id][x][which^1]=old; f[id][old]=x;
    f[id][x]=oldf; if (!gen) ch[id][oldf][ch[id][oldf][1]==old]=x;
}
void splay(int id,int x)
{
    int top=0,i;
    for (i=x;!Is_root(id,i);i=f[id][i]) stack[++top]=i;
    stack[++top]=i;
    for (i=top;i>=1;i--) pushdown(id,stack[i]);

    for (;!Is_root(id,x);rotate(id,x))
      if (!Is_root(id,f[id][x])) rotate(id,get(id,f[id][x])==get(id,x)?f[id][x]:x);
}
void access(int id,int x)
{
    int t=0;
    for (;x;t=x,x=f[id][x])
    {
        splay(id,x);
        ch[id][x][1]=t;
    }
}
void reverse(int id,int x)
{
    access(id,x);
    splay(id,x);
    deltaz[id][x]^=1;
}
int find(int id,int x)
{
    while (ch[id][x][0]) x=ch[id][x][0];
    return x;
}
bool connect(int id,int x,int y)
{
    access(id,x); splay(id,x);
    int fa1=find(id,x);
    access(id,y); splay(id,y);
    int fa2=find(id,y);
    return fa1==fa2;
}
void Link(int id,int x,int y)
{
    reverse(id,x);
    f[id][x]=y;
    splay(id,x);
    du[id][x]++; du[id][y]++;
}
void Cut(int id,int x,int y)
{
    reverse(id,x);
    access(id,y);
    splay(id,y);
    ch[id][y][0]=f[id][x]=0;
    du[id][x]--; du[id][y]--;
}
int main()
{
    int n,m,c,T,i;
    scanf("%d%d%d%d",&n,&m,&c,&T);
    int x,y,z;
    for (i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        mp[(x-1)*8000+y]=z; Link(z,x,y);
    }
    while (T--)
    {
        scanf("%d%d%d",&x,&y,&z);
        int now=8000*(x-1)+y;
        if (!mp[now]) printf("No such cable.\n");
        else if (mp[now]==z) printf("Already owned.\n");
        else if (du[z][x]==2 || du[z][y]==2) printf("Forbidden: monopoly.\n");
        else if (connect(z,x,y)) printf("Forbidden: redundant.\n");
        else 
        {
            Cut(mp[now],x,y);
            Link(z,x,y);
            mp[now]=z;
            printf("Sold.\n");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值