【CF1810E】Monsters(合并点优化)(优先队列)

洛谷链接

Monsters

题面翻译

有一个 n n n m m m 边的图,在每个点上有一个怪, a i a_i ai 表示杀死这个怪需要已经击杀的怪物数。你需要选择一个 a i = 0 a_i=0 ai=0 的点作为起点,判断是否可以杀掉图上所有的怪。在此过程中,你可以通过一条无向边 ( u , v ) (u,v) (u,v) 从点 u u u 移动到 v v v,前提是 v v v 上的怪已经被击杀或者可以被击杀。

包含 t t t 组询问。

数据范围: 1 ≤ t ≤ 1 0 4 1\le t\le 10^4 1t104 1 ≤ n , m ≤ 2 × 1 0 5 1\le n,m\le 2\times 10^5 1n,m2×105 0 ≤ a i ≤ n 0\le a_i\le n 0ain

题目描述

There is an undirected graph with $ n $ vertices and $ m $ edges. Initially, for each vertex $ i $ , there is a monster with danger $ a_{i} $ on that vertex. For a monster with danger $ a_{i} $ , you can defeat it if and only if you have defeated at least $ a_{i} $ other monsters before.

Now you want to defeat all the monsters. First, you choose some vertex $ s $ and defeat the monster on that vertex (since you haven’t defeated any monsters before, $ a_{s} $ has to be $ 0 $ ). Then, you can move through the edges. If you want to move from vertex $ u $ to vertex $ v $ , then the following must hold: either the monster on vertex $ v $ has been defeated before, or you can defeat it now. For the second case, you defeat the monster on vertex $ v $ and reach vertex $ v $ .

You can pass the vertices and the edges any number of times. Determine whether you can defeat all the monsters or not.

输入格式

Each test contains multiple test cases. The first line contains a single integer $ t $ ( $ 1 \le t \le 10^4 $ ) — the number of test cases. Their description follows.

The first line of each test case contains two integers $ n $ , $ m $ ( $ 1 \le n, m \le 2 \cdot 10^5 $ ) — the number of vertices and edges in the graph respectively.

The second line of each test case contains $ n $ integers $ a_{1}, a_{2}, \ldots, a_{n} $ ( $ 0 \le a_{i} \le n $ ) — the dangers of monsters on corresponding vertices.

For the following $ m $ lines, each line contains two integers $ u $ , $ v $ ( $ 1 \le u, v \le n $ ), describing an edge connecting vertex $ u $ and vertex $ v $ . It is guaranteed that there are no multi-edges or self-loops in the graph.

It is guaranteed that both the sum of $ n $ and the sum of $ m $ over all test cases do not exceed $ 2 \cdot 10^5 $ .

输出格式

For each test case, output “YES” if you can defeat all the monsters, or “NO” otherwise.

You can output the answer in any case (upper or lower). For example, the strings “yEs”, “yes”, “Yes”, and “YES” will be recognized as positive responses.

样例 #1

样例输入 #1

5
4 3
2 1 0 3
1 2
2 3
3 4
6 6
0 1 2 3 0 1
1 2
2 3
3 4
4 5
4 6
5 6
4 3
0 1 2 0
1 2
2 3
1 3
4 6
1 1 1 0
1 2
3 2
4 3
2 4
4 1
1 3
5 5
0 1 3 2 0
1 2
2 3
3 4
4 5
3 5

样例输出 #1

YES
YES
NO
YES
NO

提示

In the first test case, you can start at vertex $ 3 $ and defeat the monster on it, before you go to vertices $ 2 $ , $ 1 $ in this order, defeating the monsters on them as well. Then you return to vertex $ 3 $ , and go to vertex $ 4 $ , defeating the monster on it.

In the third test case, there is no path to vertex $ 4 $ if you start at vertex $ 1 $ . Also, there is no path to vertices $ 1 $ , $ 2 $ , and $ 3 $ if you start at vertex $ 4 $ .

核心思路

压缩同0点,

可证:a[i]= 0,a[j] = 0,若i可以走到j, S(a[i]) > 2*S(a[j])

所以可让n枚举变为log n

AC代码

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
const int maxn = 2e5+10;
int t;
int n,m;
vector<int> g[maxn];
int a[maxn];
int vis[maxn];
bool bfs(int x){
	priority_queue<pii, vector<pii>, greater<pii>> q;
	q.push({0,x});
	int w = 0;
	while(!q.empty()){
		pii now = q.top();
		q.pop();
		if(w >= now.first){
			w++;
			vis[now.second] = x;
			for(int i : g[now.second]){
				if(vis[i] == x)continue;
				q.push({a[i], i});
			    vis[i] = x;
			}
		}
		else{
			break;
		}
	}
	if(w == n)return 1;
	else return 0;
}
int main() {
    cin>>t;
    while(t--){
    	cin>>n>>m;
    	for(int i = 1;i <= n;i++)g[i].clear(),vis[i] = 0;
    	for(int i = 1;i <= n;i++)cin>>a[i];
    	for(int i = 1;i <= m;i++){
    		int u,v;
    		cin>>u>>v;
    		g[u].push_back(v);
    		g[v].push_back(u);
		}
		bool flag = 0;
		for(int i = 1; i <= n; i++){
			if(a[i] == 0 && !vis[i]){
				if(bfs(i)){
					cout<<"YES"<<endl;
					flag = 1;
					break;
				}
			}
		}
		if(!flag)cout<<"NO"<<endl;
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值