星球大战

博客表明关键信息都在代码里,但未给出更多具体内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

都在代码里了!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxm = 200005 ;
const int maxn = 400005 ;
int n,m,head[maxn],top,father[maxn],k,ans[maxn],dam[maxn],num,topk;   //dam[i]记为 第 i 次摧毁的是哪个点    ans[]记录某次摧毁后的联通块(这里我是倒着来存的) 
bool vis[maxn];   //vis[i]记录的是 i 点是否被摧毁 

struct edge{//这是邻接表的图 
	int next,to = -1;      //注意   to=-1   这一点由于此图是从 0 - n-1 而这里to的初值原本为 0 ,若不改为-1 再调用的时候就会多出一个 0 点 
}e[maxm << 1];  

struct edge_know {
	int st,en;
}ek[maxm << 1];  //这是题目中所给的原图 

void add_edge(int u,int v) {  //加边操作 
	e[++top].to = v;
	e[top].next = head[u] ;
	head[u] = top ;
}

int find(int x) {   //并查集的寻找  注意路径压缩 
	if(father[x] == x) return x;
	return father[x] = find(father[x]) ;
}

void unionn(int r1,int r2) {   //合并操作   个人比较喜欢写在函数里面  
	father[find(r1)] = find(r2) ;
}

int main() {
	memset(vis,0,sizeof(vis)) ;
	scanf("%d%d",&n,&m) ;
	for(int i = 0;i < n ;++i) father[i] = i;
	for(int i = 1;i <= m ;++i) {
		int x,y; 
		scanf("%d%d",&x,&y) ;
		ek[++topk].st = x; ek[topk].en = y;	add_edge(x,y) ;    //给原图加边  给邻接表加边 
		ek[++topk].st = y; ek[topk].en = x; add_edge(y,x) ;
	}
	scanf("%d",&k) ;
	for(int i = 1;i <= k ;++i)  {
		int x ; scanf("%d",&x) ;
		vis[x] = 1 ; dam[i] = x;   //离线读入摧毁的点 
	}	
	for(int i = 1;i <= m * 2;++i) {
		if(vis[ek[i].st] == 1 || vis[ek[i].en] == 1) continue;  //判断是否改边由于点的摧毁而无价值 
		if(find(ek[i].st) != find(ek[i].en)) {
			unionn(ek[i].st , ek[i].en) ;
		}
	}   //这里做的是最后状态 
	num = 1;
	for(int i = 0;i < n ;++i) 	if(father[i] == i && !vis[i]) ans[num]++;	  //最后状态的联通块 
	
	for(int i = k;i >= 1 ;--i) {
		vis[dam[i]] = 0;    //因为要把该点加入 因此取消该店的标记 
		int u = dam[i] ; num++ ;
		ans[num] = ans[num - 1] + 1;   //加入后的初值 
		for(int j = head[u]; j ;j = e[j].next) {   //遍历每个边 每个点 
			if(vis[e[j].to] == 1) continue ;  //判断 
			if(find(u) != find(e[j].to)) {   
				unionn(u,e[j].to) ;   //加入后的联通块数-1 
				ans[num]--;
			}
		}
	}
	for(int i = num;i >= 1 ;--i)  printf("%d\n", ans[i]) ;   //由于是倒着存储 因此从num开始 循环到 1 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值