codeforces 878C Tournament平衡树,好题!!!!

C. Tournament
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Recently a tournament in k kinds of sports has begun in Berland. Vasya wants to make money on the bets.

The scheme of the tournament is very mysterious and not fully disclosed. Competitions are held back to back, each of them involves two sportsmen who have not left the tournament yet. Each match can be held in any of the k kinds of sport. Loser leaves the tournament. The last remaining sportsman becomes the winner. Apart of this, the scheme can be arbitrary, it is not disclosed in advance.

Vasya knows powers of sportsmen in each kind of sport. He believes that the sportsmen with higher power always wins.

The tournament is held every year, and each year one new participant joins it. In the first tournament, only one sportsman has participated, in the second there were two sportsmen, and so on. Vasya has been watching the tournament for the last n years. Help him to find the number of possible winners for each of the n tournaments.

Input

The first line contains two integers n and k (1 ≤ n ≤ 5·1041 ≤ k ≤ 10) — the number of tournaments and the number of kinds of sport, respectively.

Each of the next n lines contains k integers si1, si2, ..., sik (1 ≤ sij ≤ 109), where sij is the power of the i-th sportsman in the j-th kind of sport. The sportsman with higher powers always wins. It's guaranteed that for any kind of sport all of these powers are distinct.

Output

For each of the n tournaments output the number of contenders who can win.

Examples
input
3 2
1 5
5 1
10 10
output
1
2
1
input
3 2
2 2
3 3
1 10
output
1
1
3
input
3 2
2 3
1 1
3 2
output
1
1
2
Note

In the first sample:

In the first tournament there is only one sportsman, and he is the winner.

In the second tournament, there are two sportsmen, and everyone can defeat another, depending on kind of sports.

In the third tournament, the third sportsman in the strongest in both kinds of sports, so he is the winner regardless of the scheme.


题解:

感觉这是一道非常好的题目。

每个人看成一个k维的向量,对于任意两个向量,依次考虑每一个维度,并且由较大的向量向较小的向量建立边。这样的话,就形成了一副图。

对图进行强连通分量的分解,强连通分量内的任意一个元素都可以成为分量内的winner。整个图化成了DAG,并且这个DAG中,入度为0的点(或强联通分量)只能有一个。

(解释:这样想,假设有两个入度为0的点,由我们建图的方式可以知道他们之间必然存在着有向边,矛盾)

所以这个入度为0的点(或强联通分量)里面包含的元素个数就都是答案。


然而每次都建图,求scc显然是不现实的,因此我们需要一个数据结构来维护DAG。

我们定义一个node结构体,表示一个组,组相当于scc。

组内的元素都可以成为该组的winner,每个组保存2个向量(小向量和大向量),其中小向量分量表示组中所有向量的该分量的最小值,大向量表示的东西恰好相反。

维护DAG可以用平衡树,重载<运算符,即node1<node2当且仅当node1大向量严格<node2的小向量:

bool operator<(const node &nd)const{
	for(int i = 0;i < k;++i){
		if(M[i] > nd.m[i]) return false;
	}
	return true;
}
每遇到一个新的node要插入时

lower_bound会找到第一个严格 < node的后面一个的位置lb

upper_bound会找到第一个严格> node的位置ub

lb 和 ub之间的 (不包含ub)任何元素都可以与新的node建立双向边的关系从而构成新的联通分量,所以把他们取出来合并到一起再丢回去。


代码:

#include <bits/stdc++.h>
using namespace std;
int n,k;
struct node{
	int sz;
	vector<int> m,M;
	node(){
		sz = 1;
		for(int i = 0;i < k;++i){
			int tmp;scanf("%d",&tmp);
			m.push_back(tmp);
			M.push_back(tmp);
		}
	}
	bool operator<(const node &nd)const{
		for(int i = 0;i < k;++i){
			if(M[i] > nd.m[i]) return false;
		}
		return true;
	}
	void merge(const node &nd){
		for(int i = 0;i < k;++i){
			m[i] = min(m[i],nd.m[i]);
			M[i] = max(M[i],nd.M[i]);
		}
		sz += nd.sz;
	}
};
set<node> st;
int main(){
	scanf("%d%d",&n,&k);
	for(int i = 0;i < n;++i){
		node nd = node();
		auto lb = st.lower_bound(nd),ub = st.upper_bound(nd);
		while(lb!= ub){
			nd.merge(*lb);
			lb = st.erase(lb);
		}
		st.insert(nd);
		printf("%d\n",(st.rbegin())->sz);
	}
	return 0;
} 







  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值