P1197 [JSOI2008]星球大战 并查集+离线

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值