codefroces 878 C. Tournament

題意

Berland要舉行n次錦標賽,第一次只有一個人,之後每一次會新
加入一個人。錦標賽中有k種運動項目,每個人在這k種項目上都有一
個能力值,每次會選擇任意兩個還未被淘汰的人進行某個項目的比
賽,能力值高的人勝出,輸的人被淘汰,直至只剩下一個人成爲冠
軍。給出每個人每個項目的能力值,保證它們兩兩不同,求每次錦標賽有多少人可能成爲冠軍。

題解

並不會做這題。。
一開始想的是,除非一個人被另外一個人碾壓,否則一定行
很快就發現,這樣是錯的。。
然後就想到,如果ii可以贏jj,那麼就iijj連一條邊
那麼一個點可以拿冠軍,當且僅當,他可以到達所有點。。
於是,我們可以強連通縮點一下,得到一個DAG。。
然後對於一個普通的DAG剩下似乎就不可做了。。
膜了題解
發現有一個很重要的性質沒有想起來
那就是這是一個競賽圖
想不起來的主要原因是確實沒做過競賽圖的題目。。
競賽圖顯然有一個重要的性質
就是你縮完點之後只有一個入度爲00的點
那麼答案就是這個強連通分量的大小!
這樣就省事很多了
每一次加入一個點,我們可以把一些聯通塊連起來
怎麼連呢
我們知道,如果x能打敗y,y也可以打敗x
那麼就可以看做一個點
我們仔細思考一個這個條件是什麼意思
如果a>=ba>=bb>=ab>=a,那麼a=ba=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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章