bzoj3562

24 篇文章 0 订阅

题意:
n个原子,初始有m条化学键,q次操作,每次加或删一条化学键,或询问当前有多少分子。 在变化过程中始终保持着一种特殊的性质:不存在这样的原子序列 a1,a2,…,an(n>3)满足 a1 与 a2、a2 与a3、……、an-1 与 an 以及 an 与 a1 都通过化学键相连,但它们之间却没有其他化学键相连的情况。
n≤5000,m≤200000,q≤10000

#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<iostream>
#include<set>
#define PII pair<int,int>
#define N 5100
#define M 210000
#define lb lower_bound
#define mp make_pair
using namespace std;
struct node{int o,x,y;}q[M];
struct node1{int pre,nex,x,y;}a[M];
set<PII> s;
set<PII>::iterator it;
int n,m,fa[N],ans,cnt,ql,num,las,f[N];
int find(int x)
{
    if(x!=fa[x]) fa[x]=find(fa[x]);
    return fa[x];
}
void merge(int x,int y)
{
    int fx=find(x),fy=find(y);
    if(fx==fy) return;
    ans--;
    fa[fx]=fy;
}
void del(int k)
{
    a[a[k].nex].pre=a[k].pre;
    a[a[k].pre].nex=a[k].nex;
}
void make()
{
    for(int i=1;i<=n;i++) fa[i]=f[i];
    ans=cnt;
    for(int i=0;i<=las;i=a[i].nex) merge(a[i].x,a[i].y);
    printf("%d\n",ans);
}
void solve()
{
    for(int i=1;i<=ql;i++)
    {
        if(q[i].o==0) make();
        else if(q[i].o==1) las++;
        else
        for(int j=0;j<=las;j=a[j].nex)
            if(a[j].x==q[i].x && a[j].y==q[i].y) {del(j);break;}
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        if(x>y) swap(x,y);
        s.insert(mp(x,y));
    }
    scanf("%d",&ql);
    for(int i=1;i<=ql;i++)
    {
        char c;scanf("%c",&c);while(c!='Q' && c!='A' && c!='D') scanf("%c",&c);
        if(c=='A' || c=='D')
        {
            if(c=='A') q[i].o=1;
            else q[i].o=-1;
            scanf("%d%d",&q[i].x,&q[i].y);
            if(q[i].x>q[i].y) swap(q[i].x,q[i].y);
            if(c=='D')
            {
                it=s.lb(mp(q[i].x,q[i].y));
                if(it==s.end()) continue;
                if((*it)==mp(q[i].x,q[i].y)) 
                {
                    s.erase(it);
                    a[++num].x=q[i].x;a[num].y=q[i].y;
                    a[num].pre=num-1;a[num].nex=num+1;
                }
            }
        }           
    }
    las=num;
    for(int i=1;i<=ql;i++) 
        if(q[i].o==1)
        {
            a[++num].x=q[i].x;a[num].y=q[i].y;
            a[num].pre=num-1;a[num].nex=num+1;
        }
    a[0].nex=1;
    for(int i=1;i<=n;i++) fa[i]=i;
    ans=n;
    for(it=s.begin();it!=s.end();it++)
    {
        int x=(*it).first,y=(*it).second;
        merge(x,y);
    }
    cnt=ans;
    for(int i=1;i<=n;i++) f[i]=fa[i];
    solve();
    return 0;
}

题解:
我看了题解!感觉被侮辱了T_T。。记录一下这愉♂快的时刻
注意所有的环都是若干三元环组成的,那么。。有什么卵用?!
q很小,那么初始m条边中受影响的最多只有q条,将不受影响的边缩起来,剩下的暴力。最多只有O(q)条边,加入暴力加,删除暴力删,询问暴力问。。复杂度O(nq+q*q)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值