【XSY2892】【GDSOI2018】谁是冠军

题目来源:noi2018模拟测试赛(二十三)T3 san

为什么noi模拟赛里会做到省选原题啊……

题意:

Description

有n个人,简单起见把他们编号为1到n,每个人有三项指标分别是攻击力,防御力和血量。现在要进行n-1场比赛,每次在剩下的人里面随机地选出两个人进行比赛,当一个人有大于等于两项指标严格大于另一个人时,这个人获得胜利。每次比赛,胜者留下,败者淘汰。

现在请你求出所有可能成为冠军(留到最后)的人。

Input

第1行有一个整数n,表示人数为n。

接下来n行,每行有三个整数$a_i,b_i,c_i$分别表示编号为i的人的攻击力,防御力和血量。

数据保证对于任意两个人的同一项指标值不会相同。

Output

按编号从小到大输出有可能成为冠军的人的编号,每行输出一个数。

Hint

对于$60\%$的数据$1\leq n\leq 5000$

对于$100\%$的数据$1\leq n\leq 100000$

题解:

首先60分很简单,暴力建图,即如果x能胜y就从x到y建有向边,最后从每个点出发看能否遍历整个图就好了;

也可以tarjan缩点之后直接找入度为0的联通块,块内的点就是答案;

但这样做依然是$O(n^2)$的,复杂度瓶颈在于边数是$O(n^2)$的,因此很容易想到线段树优化建图;

由于他的要求是至少两维小于,所以可以两两拆开来做三遍;

那么先把第一维排序,第二维离散化后开一颗权值线段树,新加入一个点i就将它连向权值在$[1,i的第二维权值-1]$内的区间;

这样子做一个点最多只会连向$O(logn)$个区间,所以能过;

注意修改具有时效性,所以要边加边连,具体见代码。

代码:

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 #include<queue>
  7 #include<stack>
  8 #define inf 2147483647
  9 #define eps 1e-9
 10 using namespace std;
 11 typedef long long ll;
 12 typedef double db;
 13 struct edge{
 14     int v,next;
 15 }a[20000001];
 16 struct uni{
 17     int a,b,c,id;
 18 }p[100001];
 19 struct node{
 20     int ls,rs,v;
 21 }t[500001];
 22 int n,tot=0,tid=0,bcc=0,tim=0,cnt,rt,dfn[6000001],low[6000001],blg[6000001],head[6000001];
 23 int ans[100001],anss=0;
 24 stack<int>s;
 25 bool cmp(uni a,uni b){
 26     return a.a<b.a;
 27 }
 28 bool _cmp(uni a,uni b){
 29     return a.b<b.b;
 30 }
 31 void add(int u,int v){
 32     //printf("Added %d %d\n",u,v);
 33     a[++tot].v=v;
 34     a[tot].next=head[u];
 35     head[u]=tot;
 36 }
 37 void build(int &u,int l,int r){
 38     u=++cnt;
 39     t[u].v=0;
 40     if(l==r)return;
 41     int mid=(l+r)/2;
 42     build(t[u].ls,l,mid);
 43     build(t[u].rs,mid+1,r);
 44 }
 45 void updata(int u,int l,int r,int p,int x){
 46     if(l==r){
 47         t[u].v=x;
 48         return;
 49     }
 50     int mid=(l+r)/2;
 51     if(p<=mid)updata(t[u].ls,l,mid,p,x);
 52     else updata(t[u].rs,mid+1,r,p,x);
 53     if(t[t[u].ls].v&&t[t[u].rs].v){
 54         t[u].v=++tid;
 55         add(tid,t[t[u].ls].v);
 56         add(tid,t[t[u].rs].v);
 57     }else t[u].v=t[t[u].ls].v+t[t[u].rs].v;
 58 }
 59 void query(int u,int l,int r,int L,int R,int id){
 60     if(!t[u].v)return;
 61     if(l==L&&r==R){
 62         add(id,t[u].v);
 63         return;
 64     }
 65     int mid=(l+r)/2;
 66     if(L<=mid)query(t[u].ls,l,mid,L,min(mid,R),id);
 67     if(mid<R)query(t[u].rs,mid+1,r,max(mid+1,L),R,id);
 68 }
 69 void link(){
 70     sort(p+1,p+n+1,cmp);
 71     cnt=0;
 72     build(rt,1,n);
 73     //puts("----12----");
 74     for(int i=1;i<=n;i++){
 75         query(rt,1,n,1,p[i].b-1,p[i].id);
 76         updata(rt,1,n,p[i].b,p[i].id);
 77     }
 78     cnt=0;
 79     build(rt,1,n);
 80     //puts("----13----");
 81     for(int i=1;i<=n;i++){
 82         query(rt,1,n,1,p[i].c-1,p[i].id);
 83         updata(rt,1,n,p[i].c,p[i].id);
 84     }
 85     sort(p+1,p+n+1,_cmp);
 86     cnt=0;
 87     build(rt,1,n);
 88     //puts("----23----");
 89     for(int i=1;i<=n;i++){
 90         query(rt,1,n,1,p[i].c-1,p[i].id);
 91         updata(rt,1,n,p[i].c,p[i].id);
 92     }
 93 }
 94 void tarjan(int u){
 95     dfn[u]=low[u]=++tim;
 96     s.push(u);
 97     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
 98         int v=a[tmp].v;
 99         if(!dfn[v]){
100             tarjan(v);
101             low[u]=min(low[u],low[v]);
102         }else if(!blg[v])low[u]=min(low[u],dfn[v]);
103     }
104     if(low[u]==dfn[u]){
105         blg[u]=++bcc;
106         int nw=s.top();
107         while(nw!=u){
108             nw=s.top();
109             blg[nw]=bcc;
110             s.pop();
111         }
112     }
113 }
114 int main(){
115     memset(head,-1,sizeof(head));
116     scanf("%d",&n);
117     for(int i=1;i<=n;i++){
118         scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
119         p[i].id=i;
120     }
121     tid=n;
122     link();
123     for(int i=1;i<=n;i++){
124         if(!dfn[i]){
125             tarjan(i);
126         }
127     }
128     for(int i=1;i<=n;i++){
129         if(blg[i]==bcc)ans[++anss]=i;
130     }
131     for(int i=1;i<=anss;i++){
132         printf("%d\n",ans[i]);
133     }
134     return 0;
135 }
posted @ 2018-12-07 11:51  DCDCBigBig  阅读(377)  评论(0编辑  收藏  举报