题目大意:
n个人参加竞技比赛。比赛由三种模式a,b,c,每个人在每种模式下有对应的权值a[i]b[i]c[i]。举行n−1场比赛,每场比赛主办方可以选择两个人决斗,能力值低的人淘汰。这样保证n-1场比赛过后,只会有一个winner。q 个询问,询问第x个人,问主办方有没有一种方式可以使他成为winner。(n=1e5,q=1e5)
解题报告:
wjh大佬写的贪心也能过,但是这题正解是缩点。其实任意一种模式都是无关紧要的,只要有一种属性x比y大,则可以连边x->y。而且对于所有比y小的元素你只需要和比他小的最大的那个元素连边就可以了,因为战胜的关系是具有传递性的,所以不需要都连边,也不能和任意一个比他小的元素连边,然后缩点,对于每一个大点,如果入度为0那就是可以成为冠军的点。
AC代码:
#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 ;
}