[CF1369E]DeadLee

89 篇文章 0 订阅

题目

传送门 to luogu

思路

唯一可能导致顾客愤怒的菜品,一定供不应求。倘若该菜品的数量足够每个喜欢它的人拿一份,那么所有喜欢它的人都至少有这个菜可以拿,我们便安排这些人最后取。或者说,我们忽略他们,因为他们不会骂骂咧咧地吃掉厨师,尽管吃饭的时候无论说话还是骂人都不大清楚。

忽略他们之后,剩下的菜品就可以继续上面的操作了,因为那些友善的人已经被忽略了。

反复执行,最后还是所有的菜品都不够用,那么厨师死定了。原因是,最后一个人一定拿不到菜,否则存在一道菜是数量充足的。

只需要用类似拓扑排序的方法删掉每一道菜即可。人的顺序就是删掉顺序的逆序。复杂度 O ( n + m ) \mathcal O(n+m) O(n+m)

代码

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
template < typename T >
void getMax(T&a,const T&b){if(a<b)a=b;}
template < typename T >
void getMin(T&a,const T&b){if(b<a)a=b;}

const int MaxN = 100005;
int a[MaxN], w[MaxN], n, m;

struct Edge{
	int to, nxt;
	Edge(int T=0,int N=0){
		to = T, nxt = N;
	}
} edge[MaxN<<2];
int head[MaxN], cntEdge;
void addEdge(int a,int b){
	edge[cntEdge] = Edge(b,head[a]);
	head[a] = cntEdge ++;
	edge[cntEdge] = Edge(a,head[b]);
	head[b] = cntEdge ++;
}

bool died[MaxN], done[MaxN<<1];
vector< int > v, ans;
int main(){
	n = readint(), m = readint();
	for(int i=1; i<=n; ++i)
		w[i] = readint();
	for(int i=1; i<=n; ++i)
		head[i] = -1;
	for(int i=1,a,b; i<=m; ++i){
		a = readint(), b = readint();
		addEdge(a,b); -- w[a], -- w[b];
	}
	for(int i=1; i<=n; ++i)
		if(w[i] >= 0){
			v.push_back(i);
			died[i] = true;
		}
	while(!v.empty()){
		int t = v.back(); v.pop_back();
		for(int i=head[t]; ~i; i=edge[i].nxt){
			++ w[edge[i].to];
			if(!done[(i>>1)+1])
				ans.push_back((i>>1)+1);
			done[(i>>1)+1] = true;
			if(died[edge[i].to]) continue;
			if(w[edge[i].to] >= 0){
				died[edge[i].to] = true;
				v.push_back(edge[i].to);
			}
		}
	}
	for(int i=1; i<=n; ++i)
		if(!died[i]){
			puts("DEAD");
			return 0;
		}
	puts("ALIVE");
	while(!ans.empty()){
		printf("%d ",ans.back());
		ans.pop_back();
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值