codefroces 878 C. Tournament

版权声明:本文为博主原创文章,爱转载的表明出处就好. https://blog.csdn.net/qq_36797743/article/details/83536845

题意

Berland要举行n次锦标赛,第一次只有一个人,之后每一次会新
加入一个人。锦标赛中有k种运动项目,每个人在这k种项目上都有一
个能力值,每次会选择任意两个还未被淘汰的人进行某个项目的比
赛,能力值高的人胜出,输的人被淘汰,直至只剩下一个人成为冠
军。给出每个人每个项目的能力值,保证它们两两不同,求每次锦标赛有多少人可能成为冠军。

题解

并不会做这题。。
一开始想的是,除非一个人被另外一个人碾压,否则一定行
很快就发现,这样是错的。。
然后就想到,如果 i i 可以赢 j j ,那么就 i i j j 连一条边
那么一个点可以拿冠军,当且仅当,他可以到达所有点。。
于是,我们可以强连通缩点一下,得到一个DAG。。
然后对于一个普通的DAG剩下似乎就不可做了。。
膜了题解
发现有一个很重要的性质没有想起来
那就是这是一个竞赛图
想不起来的主要原因是确实没做过竞赛图的题目。。
竞赛图显然有一个重要的性质
就是你缩完点之后只有一个入度为 0 0 的点
那么答案就是这个强连通分量的大小!
这样就省事很多了
每一次加入一个点,我们可以把一些联通块连起来
怎么连呢
我们知道,如果x能打败y,y也可以打败x
那么就可以看做一个点
我们仔细思考一个这个条件是什么意思
如果 a > = b a>=b b > = a b>=a ,那么 a = b a=b
显然,在这里等号具有传递性!!!
那么我们其实加入一个点,就会使得一些原来不相等的点相等
我们用set定义小于号
就可以得到和x相等的点的编号了,连在一起即可

感觉这题无论是竞赛题的性质还是用set来维护都十分地巧妙

CODE:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
int n,k;
struct qq
{
	int mx[11],mn[11];
	int size;
};
bool operator < (qq x,qq y)
{
	for (int u=1;u<=k;u++)
		if (x.mx[u]>y.mn[u])
			return false;
	return true;
}
set<qq> s;
int read ()
{
	char ch=getchar();int x=0;
	while (ch<'0'||ch>'9')	ch=getchar();
	while (ch>='0'&&ch<='9')	{x=x*10+ch-'0';ch=getchar();}
	return x;
}
int main()
{
	n=read();k=read();
	for (int u=1;u<=n;u++)
	{
		qq x;
		for (int i=1;i<=k;i++)
		{
			x.mn[i]=x.mx[i]=read();
			x.size=1;
		}
		set<qq> :: iterator  l,r;
		l=s.lower_bound(x);
		r=s.upper_bound(x);
		while (l!=r)
		{
			x.size=x.size+(*l).size;
			for (int u=1;u<=k;u++)
			{
				x.mn[u]=min(x.mn[u],(*l).mn[u]);
				x.mx[u]=max(x.mx[u],(*l).mx[u]);
			}
			s.erase(l++);
			//l++;
		}
		s.insert(x);
		printf("%d\n",(*s.rbegin()).size);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36797743/article/details/83536845