【2019南昌邀请赛现场赛 - G】Winner(思维、图论+缩点)

题目链接: https://nanti.jisuanke.com/t/40259

Ichuan really likes to play games, so he organized a game competition with NN participating players.

Follows are the rule of the game competition.

  1. There are three modes in the game, in each mode, players have different ability values, in addition, each player may have different ability value in different mode.

  2. There are a total of N-1N−1 matches. In each match, two players who have not yet been eliminated will play against each other in one of the modes. The player who has high ability in this mode will win, and the other one will be eliminated.

  3. The only player who remains in the game after all N-1N−1 matches will be the winner.

As the organizer of the game, ichuan can manipulate the result of the game. Namely, for each match, he can choose both players and match mode. Of course, he can only choose players who have not yet been eliminated.

Ichuan has some friends, some of them will ask him: "Does player XX will be the winner?" Answering this question will give you a lot of reward, so you need to write a program which can answer these questions.

Input

The first line contains integers NN and Q (1 \le N,Q \le 10^5)Q(1≤N,Q≤105), the number of players and the number of requests.

The next three lines, each line contains NN integers, the X_{th}Xth​ integer Y(1 \le Y \le 10^6)Y(1≤Y≤106)represents the ability value of player XX in this mode.,

The next qq lines, each line only has one integer X(1 \le X \le n)X(1≤X≤n), which means ichuan's friend wants to know if player XX can be the winner.

Output

For each query, if player XX has a chance to be the winner, output "YES", otherwise output "NO"

输出时每行末尾的多余空格,不影响答案正确性

样例输入复制

4 4 
1 2 3 4
1 2 4 3
2 1 3 4
1 
2 
3
4

样例输出复制

NO
NO 
YES 
YES   

题解:

n个人参加竞技比赛,比赛由三种模式,每种模式,n 个人有3种不同得能力值,举行n−1场比赛,每场比赛选择两个人决斗,能力值低的人淘汰,q 个询问,询问该角色是否有可能生存到最后。

思路:

正解好像是图论,建图然后缩点。

我用了贪心的方法,加上有个人已经有可能是冠军了,那么如果一个人的某一能力,能战胜这个冠军,那么他也一定可以成为冠军。基于这个思想,先对每一种能力值排序,最后一个人一定可以成为冠军,然后我们可以得到一个成为冠军的能力值的最小值(暂时的),然后只要某一能力比这个能力的最小值小,那么他也可以成为冠军,然后用它的值来更新最小值。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
#define mod (1000000007)
using namespace std;
typedef long long ll;
const int maxn=200100;
set<int> st;
struct node{
	int a,b,c,id;
	void in(node tm){
		a=tm.a;
		b=tm.b;
		c=tm.c;
		id=tm.id;
	}
}a1[maxn],a2[maxn],a3[maxn];
int cmp1(node a,node b){
	return a.a<b.a;
}
int cmp2(node a,node b){
	return a.b<b.b;
}

int cmp3(node a,node b){
	return a.c<b.c;
}

int main()
{
	int n,q;
	scanf("%d%d",&n,&q);	
	for(int i=1;i<=n;i++) scanf("%d",&a1[i].a),a1[i].id=i;
	for(int i=1;i<=n;i++) scanf("%d",&a1[i].b);
	for(int i=1;i<=n;i++) scanf("%d",&a1[i].c);
	for(int i=1;i<=n;i++){
		a2[i].in(a1[i]);
		a3[i].in(a1[i]);
	}
	sort(a1+1,a1+n+1,cmp1);
	sort(a2+1,a2+n+1,cmp2);
	sort(a3+1,a3+n+1,cmp3);
	int la=n,lb=n,lc=n;
	int ma=min(a1[n].a,min(a2[n].a,a3[n].a));
	int mb=min(a1[n].b,min(a2[n].b,a3[n].b));
	int mc=min(a1[n].c,min(a2[n].c,a3[n].c));
	while(1){
		int ff=0; 
		for(;la>0&&a1[la].a>=ma;la--){
			ff=1;
			st.insert(a1[la].id);
			ma=min(ma,a1[la].a);
			mb=min(mb,a1[la].b);
			mc=min(mc,a1[la].c);
		}
		for(;lb>0&&a2[lb].b>=mb;lb--){
			ff=1;
			st.insert(a2[lb].id);
			ma=min(ma,a2[lb].a);
			mb=min(mb,a2[lb].b);
			mc=min(mc,a2[lb].c);
		}
		for(;lc>0&&a3[lc].c>=mc;lc--){
			ff=1;
			st.insert(a3[lc].id);
			ma=min(ma,a3[lc].a);//用新加入的数更新最小值,这个值应该a3[lc],但是a1[lc] 就变成另一个数了 
			mb=min(mb,a3[lc].b);
			mc=min(mc,a3[lc].c);
		}
		if(!ff) break;
	}
	
	
	while(q--){
		int x;
		scanf("%d",&x);
		if(st.find(x)==st.end()) puts("NO");
		else puts("YES");
	}
	return 0;
}

队友的图论做法:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define FF first
#define SS second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
struct Node {
	int a,b,c;
	int id;
} R[MAX];
bool cmp1(Node a,Node b) {
	return a.a < b.a;
}
bool cmp2(Node a,Node b) {
	return a.b < b.b;
}
bool cmp3(Node a,Node b) {
	return a.c < b.c;
}
int n,q;
vector<int> vv[MAX];
int DFN[MAX],LOW[MAX],stk[MAX],vis[MAX],clk,Index,scc,col[MAX];
int in[MAX],ans[MAX];
void tarjan(int x) {
	DFN[x] = LOW[x] = ++clk;stk[++Index] = x;vis[x] = 1;
	for(int i = 0; i<vv[x].size(); i++) {
		int v = vv[x][i];
		if(!DFN[v]) {
			tarjan(v);LOW[x] = min(LOW[x],LOW[v]);
		}
		else if(vis[v]) LOW[x] = min(LOW[x],DFN[v]);
	}
	if(LOW[x] == DFN[x]) {
		scc++;
		while(1) {
			int tmp = stk[Index--];vis[tmp] = 0;
			col[tmp] = scc;
			if(tmp == x) break;			
		}		
	}	
}
int main()
{
	cin>>n>>q;
	for(int i = 1; i<=n; i++) scanf("%d",&R[i].a),R[i].id = i;
	for(int i = 1; i<=n; i++) scanf("%d",&R[i].b);
	for(int i = 1; i<=n; i++) scanf("%d",&R[i].c);
	sort(R+1,R+n+1,cmp1);
	for(int i = 2; i<=n; i++) vv[R[i].id].pb(R[i-1].id);
	sort(R+1,R+n+1,cmp2);
	for(int i = 2; i<=n; i++) vv[R[i].id].pb(R[i-1].id);
	sort(R+1,R+n+1,cmp3);
	for(int i = 2; i<=n; i++) vv[R[i].id].pb(R[i-1].id);
	for(int i = 1; i<=n; i++) if(!DFN[i]) tarjan(i);
	for(int u = 1; u<=n; u++) {
		for(int j = 0; j<vv[u].size(); j++){
			int v = vv[u][j];
			if(col[u] != col[v]) in[col[v]]++;
		}
	}
	while(q--) {
		int x; scanf("%d",&x);
		if(in[col[x]] == 0) printf("YES\n");
		else printf("NO\n");
	}
	return 0 ;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值