BZOJ 3562: [SHOI2014]神奇化合物 并查集+dfs

点击打开链接

注意到20w条边,但是询问只有1w,所以有很多边是从头到尾不变的。

首先离线处理,将从未删除的边缩点,缩点后的图的点数不会超过2w,对于每一次add或者delete,直接dfs看是否能从a走到b,然后维护一个ans。

数据不强,不然这种复杂度起码要跑10s。。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define N 5001
#define M 530005
struct node2
{
    char q;
    int a,b;
}f[200005],Q[10005];
struct node
{
    int v,next;
}edge[M];
int head[N],set[N];
bool d[N][N],v[N];
int e[N][N];
int id,ans;
void add(int a,int b)
{
    edge[id].v=b;
    edge[id].next=head[a];
    head[a]=id++;
}
void init(int n)
{
    memset(head,-1,sizeof(head));
    id=ans=0;
	for(int i=1;i<=n;i++)set[i]=i;
}
int find(int x)
{
    if(x!=set[x]) return set[x]=find(set[x]);
    return set[x];
}
void merge(int x,int y)
{
	set[find(y)]=find(x);
}

bool dfs(int a,int b)
{
    if(a==b) return true;
    for(int i=head[a];~i;i=edge[i].next)
    {
        int to=edge[i].v;
        if(e[a][to]>0&&!v[to])
        {
            v[to]=true;
            if(dfs(to,b)) return true;
        }
    }
    return false;
}
int n;
void addedge(int a,int b)
{
    memset(v,false,sizeof(v));
    if(!dfs(a,b)) ans--;
    e[a][b]++;
    e[b][a]++;
    add(a,b);
    add(b,a);
}
void del(int a,int b)
{
    memset(v,false,sizeof(v));
    e[a][b]--;
    e[b][a]--;
    if(!dfs(a,b)) ans++;
}
inline int ReadInt()
{
    char ch = getchar();
    int data = 0;
    while (ch < '0' || ch > '9')
    {
        ch = getchar();
    }
    do
    {
        data = data*10 + ch-'0';
        ch = getchar();
    }while (ch >= '0' && ch <= '9');
        return data;
}
int main()
{
    int m,a,b,q;
    n=ReadInt();
    m=ReadInt();
    init(n);
    for(int i=1;i<=m;i++)
    {
        f[i].a=ReadInt();
        f[i].b=ReadInt();
    }
    q=ReadInt();
    for(int i=1;i<=q;i++)
    {
        scanf("%s",&Q[i].q);
        if(Q[i].q!='Q')
        {
            Q[i].a=ReadInt();
            Q[i].b=ReadInt();
            if(Q[i].q=='D') d[Q[i].a][Q[i].b]=d[Q[i].b][Q[i].a]=true;
        }
    }
    for(int i=1;i<=m;i++)
    {
        if(!d[f[i].a][f[i].b]) merge(f[i].a,f[i].b);
    }
    for(int i=1;i<=n;i++)
    {
        if((set[i]=find(i))==i) ans++;
    }
    for(int i=1;i<=m;i++)
    {
        if(set[f[i].a]!=set[f[i].b]) addedge(set[f[i].a],set[f[i].b]);
    }
    for(int i=1;i<=q;i++)
    {
        if(Q[i].q=='Q') printf("%d\n",ans);
        else if(Q[i].q=='D') del(set[Q[i].a],set[Q[i].b]);
        else addedge(set[Q[i].a],set[Q[i].b]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TommyTT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值