bzoj 3562: [SHOI2014]神奇化合物

大水题来啦!!
就是一个暴力题啊!!!
一开始想到了。。。
但是由于我太弱了,觉得10000*10000会超时,于是就GG了。。
不知道为什么。。我都做了这么多题了。。还不是非常清楚多少复杂度会超时。。看来还是我太弱了啊

这题的解法:
离线缩点啊!!!
然后因为询问少,所以有些边是永远在的,吧这些搞着先就好了
时间 O(qq+qn)

code:

#include<cstdio>
#include<cstring>
#define swap(x,y) {int tt=x;x=y;y=tt;}
const int N=5005;
const int Q=10005;
int n,m,q;
bool g[N][N];//是否连通
int f[N];//并查集缩点
int tt[N][N],lalal;//会变的边   这条边的新编号
int X[Q],Y[Q];
bool ooo[Q];
struct qq
{
    char ss[5];int x,y;
}s[Q];
int ff[N];
int find (int x){return f[x]==x?f[x]:f[x]=find(f[x]);}
int find1 (int x){return ff[x]==x?ff[x]:ff[x]=find1(ff[x]);}
int ans[Q],cnt;
bool ok[N];
int main()
{
    memset(f,false,sizeof(f));
    scanf("%d%d",&n,&m);
    for (int u=1;u<=n;u++) f[u]=u;
    for (int u=1;u<=m;u++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if (x>y) swap(x,y);
        g[x][y]=true;
    }
    scanf("%d",&q);
    memset(tt,-1,sizeof(tt));
    for (int u=1;u<=q;u++)
    {
        scanf("%s",s[u].ss);
        if (s[u].ss[0]=='Q') continue;
        scanf("%d%d",&s[u].x,&s[u].y);
        if (s[u].x==s[u].y) {u--;q--;continue;}
        if (s[u].x>s[u].y) swap(s[u].x,s[u].y);
        g[s[u].x][s[u].y]=(s[u].ss[0]=='A');
        if (tt[s[u].x][s[u].y]==-1)
        {
            tt[s[u].x][s[u].y]=++lalal;
            X[lalal]=s[u].x;Y[lalal]=s[u].y;
        }
    }   
    for (int u=1;u<=n;u++)
    {
        for (int i=u+1;i<=n;i++)
        {
            if (g[u][i]==true&&tt[u][i]==-1)
            {
                int fx=find(u),fy=find(i);
                if (fx==fy) continue;
                f[fx]=fy;
            }
        }
    }
    for (int u=1;u<=lalal;u++)  ooo[u]=g[X[u]][Y[u]];
    cnt=0;
    memset(ok,false,sizeof(ok));
    for (int O=q;O>=1;O--)
    {
        if (s[O].ss[0]=='Q')
        {
            cnt++;ans[cnt]=0;
            for (int i=1;i<=n;i++) ff[i]=f[i];
            for (int i=1;i<=lalal;i++)
            {
                if (ooo[i]==true)
                {
                    int fx=find1(X[i]),fy=find1(Y[i]);
                    if (fx==fy) continue;
                    ff[fx]=fy;
                }
            }
            for (int u=1;u<=n;u++) ok[find1(u)]=true;
            for (int u=1;u<=n;u++)
                if (ok[u])
                {
                    ans[cnt]++;
                    ok[u]=false;
                }

        }
        else ooo[tt[s[O].x][s[O].y]]=!(s[O].ss[0]=='A');
    }
    for (int u=cnt;u>=1;u--) printf("%d\n",ans[u]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值