Codeforces878C. Tournament

$n \leq 50000$个人,每个人有$K \leq 10$个属性,现对每一个前缀问:进行比赛,每次任意两人比任意属性,小的淘汰(保证同一属性不会出现两个相同的数),最终有几个人有可能获胜。

明显是一个竞赛图了,缩完点就是求拓扑序最高那个强连通分量的大小。现在要一个一个把人加入。

可以观察到,缩完点之后,两个分量之间一定有边,表示一个分量“完胜”另一个,就是不管比哪个属性这个分量里的人都能赢另外一个。所以把分量按某个属性的最小值排序的话,任意一个属性与此同时都是按最小值排序的,同时也是按任意属性最大值排序的。

加入一个人,他可能战胜一些分量(某个属性大于这个分量的最小值),可能被一些分量战胜(某个属性小于这个分量的最大值),因此可能合并一些分量。需要把分量值按从小到大一直维持有序,并插入删除点,用set即可。一个分量的信息可以存在数组中,找分量中的一个“代表”存,会使代码简洁。

 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 //#include<math.h>
 5 #include<set>
 6 //#include<queue>
 7 //#include<vector>
 8 #include<algorithm>
 9 #include<stdlib.h>
10 using namespace std;
11 
12 #define LL long long
13 int qread()
14 {
15     char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
16     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
17 }
18 
19 //Pay attention to '-' , LL and double of qread!!!!
20 
21 int n,K;
22 #define maxn 50011
23 int a[maxn][13],b[maxn][13],size[maxn];
24 struct snode
25 {
26     int id,v;
27     bool operator < (const snode &b) const {return v<b.v;}
28 };
29 set<snode> s;
30 
31 bool Win(int x,int y)
32 {
33     for (int i=1;i<=K;i++) if (b[x][i]>a[y][i]) return 1;
34     return 0;
35 }
36 
37 int main()
38 {
39     n=qread(); K=qread();
40     for (int i=1;i<=n;i++)
41         for (int j=1;j<=K;j++)
42             a[i][j]=b[i][j]=qread();
43     for (int i=1;i<=n;i++)
44     {
45         size[i]=1;
46         set<snode>::iterator it;
47         while (!s.empty())
48         {
49             it=s.lower_bound((snode){0,a[i][1]});
50             if (it==s.end()) break;
51             int u=(*it).id;
52             if (Win(i,u))
53             {
54                 size[i]+=size[u];
55                 for (int j=1;j<=K;j++)
56                     a[i][j]=min(a[i][j],a[u][j]),b[i][j]=max(b[i][j],b[u][j]);
57                 s.erase(it);
58             }
59             else break;
60         }
61         while (!s.empty())
62         {
63             it=s.lower_bound((snode){0,a[i][1]});
64             if (it==s.begin()) break;
65             it--; int u=(*it).id;
66             if (Win(u,i))
67             {
68                 size[i]+=size[u];
69                 for (int j=1;j<=K;j++)
70                     a[i][j]=min(a[i][j],a[u][j]),b[i][j]=max(b[i][j],b[u][j]);
71                 s.erase(it);
72             }
73             else break;
74         }
75         s.insert((snode){i,a[i][1]});
76         printf("%d\n",size[(*--s.end()).id]);
77     }
78     return 0;
79 }
View Code

 

posted @ 2018-06-16 10:28  Blue233333  阅读(239)  评论(0编辑  收藏  举报