题目描述
n≤5000,q≤10000
题目大意
就是有n个点,
有加边,删边操作,
询问当前联通块格式。
题解
边虽然很多,但是实际上有用的不多。
假设有两个联通块,之间存在着两条边。
暂时不考虑联通块里面的边的变化,
那么这两条边中较早删去的那一条边就没有意义了。
基于这个思想,
给每一条边有个边权,
即q-它被删去的时间,如果某一条边不被删去,那么它的边权就是0。
有了边权就可以做最小生成树。
每次只保留最多n-1条边,
删除就判断这条边是否最小生成树上面,是就直接去掉,否则就不用管。
加入一条边就O(n)的复杂度重构一棵最小生成树,
询问就可以直接输出了。
code
#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 5003
#define M 103
#define db double
#define P putchar
#define G getchar
#define inf 998244353
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
struct node
{
int x,y,z;
};
bool operator ==(node a,node b)
{
return a.x==b.x && a.y==b.y && a.z==b.z;
}
int n,m,tot,f[N][N],x,y,cz[N*2],tr,opt,q;
int fa[N],ans;
node use[N],t[N],a[N*40+10000];
bool cmp(node a,node b)
{
return a.z<b.z;
}
int get(int x)
{
return fa[x]=(fa[x]==x?x:get(fa[x]));
}
void mst(node p)
{
int m=0;
for(int i=1;i<=tr;i++)
{
if(p.z<use[i].z)t[++m]=p,p.z=2147483647;
t[++m]=use[i];
}
if(p.z!=2147483647)t[++m]=p;
for(int i=1;i<=n;i++)
fa[i]=i;
tr=0;
for(int i=1;i<=m;i++)
{
x=get(t[i].x);
y=get(t[i].y);
if(x!=y)
{
fa[x]=y;
use[++tr]=t[i];
}
}
}
int main()
{
freopen("compound.in","r",stdin);
freopen("compound.out","w",stdout);
read(n);read(m);
for(int i=1;i<=m;i++)
read(a[i].x),read(a[i].y),f[a[i].x][a[i].y]=f[a[i].y][a[i].x]=i;
read(q);tot=m;
for(int i=1;i<=q;i++)
{
for(ch=G();ch!='Q' && ch!='D' && ch!='A';ch=G());
if(ch=='A')
{
cz[i]=1;tot++;
read(a[tot].x);
read(a[tot].y);
f[a[tot].x][a[tot].y]=f[a[tot].y][a[tot].x]=tot;
}else
if(ch=='D')
{
cz[i]=2;tot++;
read(x);
read(y);
a[f[x][y]].z=q+m-i;
a[tot]=a[f[x][y]];
}else
if(ch=='Q')cz[i]=3;
}
for(int i=1;i<=n;i++)
fa[i]=i;
sort(a+1,a+1+m,cmp);
for(int i=1;i<=n;i++)
fa[i]=i;
tr=0;
for(int i=1;i<=m;i++)
{
x=get(a[i].x);
y=get(a[i].y);
if(x!=y)
{
fa[x]=y;
use[++tr]=a[i];
}
}
opt=m;
for(int i=1;i<=q;i++)
{
if(cz[i]==1)mst(a[++opt]);else
if(cz[i]==2)
{
opt++;
for(int j=1;j<=tr;j++)
if(a[opt]==use[j])
{
for(int k=j+1;k<=tr;k++)
use[k-1]=use[k];
tr--;
break;
}
}else
if(cz[i]==3)write(n-tr),P('\n');
}
return 0;
}