P1197 [JSOI2008]星球大战 并查集+离线
给爷整懵了,这是TM人做的?删元素的并查集??
实在熬不下去了看了一下题解就发现好简单
做法:一共要删除k个点,对这k个点从后往前遍历,也就是说先假设这k个点都删除了,然后一个个点加进去,这时候就可以用简单的并查集合并操作了
提供了一种解题思路,化正为反,反向做就会简单很多
代码:
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<queue>
#include<map>
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x<b;x++)
#define W(x) printf("%d\n",x)
#define WW(x) printf("%lld\n",x)
#define pi 3.14159265358979323846
#define mem(a,x) memset(a,x,sizeof a)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int maxn=4e5+7;
const int INF=1e9;
const ll INFF=1e18;
int fa[maxn],n,m,a,b,x,k,num,ans[maxn],D[maxn];
struct Edge
{
int u,v,id;
}edge[maxn];
bool cmp(Edge a,Edge b)
{
return a.id<b.id;
}
int find(int x)
{
if (fa[x]==x)return x;
else return fa[x]=find(fa[x]);
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if (x!=y)
{
fa[x]=y;
num--;
}
}
int main()
{
scanf("%d%d",&n,&m);
num=n;
rep(i,1,n)fa[i]=i;
rep(i,1,m)
{
scanf("%d%d",&edge[i].u,&edge[i].v);
edge[i].u++;edge[i].v++;
}
scanf("%d",&k);
rep(i,1,k)
{
scanf("%d",&x);
D[x+1]=k-i+1;
}
rep(i,1,m)edge[i].id=max(D[edge[i].u],D[edge[i].v]);
sort(edge+1,edge+1+m,cmp);//便于加边
for (int j=0,i=1;j<=k;j++)
//当j=0时,也就是合并未被删除的点的过程(edge[i].id都为0)
{
while (edge[i].id==j)
{
unite(edge[i].u,edge[i].v);
i++;
}
ans[j]=num-(k-j);//(k-j)表示删除的点的个数
}
for (int j=k;j>=0;j--)W(ans[j]);
return 0;
}