P7033 [NWRRC 2016] CodeCoder vs TopForces

传送门

题目描述

在 Byteland,竞赛编程非常流行。事实上,每位 Byteland 的公民都在两个编程网站------CodeCoder 和 TopForces 上注册。每个网站都有自己专有的评分系统。每位公民在每个网站上都有一个唯一的整数评分,代表他们的技能。评分越高,技能越好。

Byteland 的人天生乐观。公民 A 认为,如果存在一个 Byteland 公民的序列 A = P 0 , P 1 , . . . , P k = B A = P_{0}, P_{1},...,P_{k} = B A=P0,P1,...,Pk=B,对于某个 k ≥ 1 k \ge 1 k≥1,使得对于每个 i ( 0 ≤ i < k ) i (0 \le i < k) i(0≤i<k), P i P_{i} Pi 在一个或两个网站上的评分都高于 P i + 1 P_{i+1} Pi+1,那么他就有机会在编程比赛中击败公民 B。

每位 Byteland 公民都想知道他们在编程比赛中可能击败多少其他公民。

输入格式

输入的第一行包含一个整数 n n n------公民的数量 ( 1 ≤ n ≤ 100000 ) (1 \le n \le 100 000) (1≤n≤100000)。接下来的 n n n 行包含关于评分的信息。第 i i i 行包含两个整数 C C i CC_{i} CCi 和 T F i TF_{i} TFi------第 i i i 位公民在 CodeCoder 和 TopForces 上的评分 ( 1 ≤ C C i , T F i ≤ 10 6 ) (1 \le CC_{i}, TF_{i} \le 10^{6}) (1≤CCi,TFi≤106)。每个网站上的所有评分都是不同的。

输出格式

对于每位公民 i i i,输出一个整数 b i b_{i} bi------他们在编程比赛中可能击败的其他公民数量。每个 b i b_{i} bi 应该单独一行输出,顺序与输入中给出的公民顺序相同。

输入输出样例 #1

输入 #1

复制代码
4
2 3
3 2
1 1
4 5

输出 #1

复制代码
2
2
0
3

题意

有 n n n 个人,他们每人都有两个评分 C C i , T F i CC_i,TF_i CCi,TFi。

若公民序列 A = P 0 , P 1 , . . . , P k = B A = P_{0}, P_{1},...,P_{k} = B A=P0,P1,...,Pk=B,满足每一个 P i P_i Pi 至少有一个分数严格大于 P i + 1 P_{i + 1} Pi+1,则称为 A A A 能击败 B B B。

求每个公民可能击败多少其他公民。

思路

我们先推导能击败的等价条件:

  1. 若 X X X 能击败 Y Y Y, Y Y Y 能击败 Z Z Z,则 X X X 能击败 Z Z Z;

  2. 记 M ( i ) M(i) M(i) 为 i i i 能击败的所有人中最大的 T F TF TF 值,则:

    • i i i 能击败所有 T F ≤ M ( i ) TF \leq M(i) TF≤M(i) 的人;
    • i i i 无法击败任何 T F > M ( i ) TF > M(i) TF>M(i) 的人。

由于每个人分数唯一,我们将所有人按 C C CC CC 升序排序:

  • 排序后第 i i i 个人的 C C CC CC 是第 i i i 小的,前 i − 1 i-1 i−1 个人的 C C CC CC 都更小,因此这 i − 1 i-1 i−1 个人都会被第 i i i 个人击败;

  • 预处理前缀最大 T F TF TF: m a x n i = max ⁡ ( m a x n i − 1 , T F i ) maxn_i = \max(maxn_{i-1}, TF_i) maxni=max(maxni−1,TFi),这是第 i i i 个人能有的最大 T F TF TF 值。

排序后 C C CC CC 递增,后面的人会影响前面的人,因此我们需要从后往前遍历:

  1. 用树状数组维护 T F TF TF 坐标上的「最大击败人数」;

  2. 对第 i i i 个人:查询 T F < m a x n i TF < maxn_i TF<maxni 的最大击败人数,与 i − 1 i-1 i−1 取最大值,即为最终答案;

  3. 将当前 T F TF TF 位置更新为该答案。

复杂度取决于排序的 O ( n log ⁡ n ) ( n = 10 5 ) O(n \log n)(n = 10^5) O(nlogn)(n=105) 和树状数组的 O ( n log ⁡ V ) ( V = 10 6 ) O(n \log V)(V = 10^6) O(nlogV)(V=106),所以总复杂度 O ( n log ⁡ V ) O(n \log V) O(nlogV),时间复杂度是可行的。

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
struct did
{
	int cc,tf,id,maxn;//每个公民的两种分数、输入时的编号以及前缀最大
	bool operator<(did other)const//重载运算符,按 CC 升序排序
	{
		return cc<other.cc;
	}
}p[1000010];
int n,c[1000010],ans[1000010];
int lowbit(int i)
{
	return (-i)&i;
}
void add(int i,int z)
{
	for(;i<=1000001;i+=lowbit(i))
		c[i]=max(c[i],z);
}
int sum(int i)
{
	int ans=0;
	for(;i>0;i-=lowbit(i))
		ans=max(ans,c[i]);
	return ans;
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>p[i].cc>>p[i].tf;
		p[i].id=i;//记录输入时的编号
	}
	sort(p+1,p+1+n);//升序排序
	for(int i=1;i<=n;i++)
		p[i].maxn=max(p[i-1].maxn,p[i].tf);//预处理前缀最大 TF
	for(int i=n;i>=1;i--)//从后往前
	{
		ans[p[i].id]=max(i-1,sum(p[i].maxn-1));//求出最终答案
		add(p[i].tf,ans[p[i].id]);//更新答案
	}
	for(int i=1;i<=n;i++)
		cout<<ans[i]<<'\n';
	return 0;
}
相关推荐
cpp_25011 个月前
P3374 【模板】树状数组 1
数据结构·c++·算法·题解·洛谷·树状数组
罗湖老棍子2 个月前
【 例 1】区间和(信息学奥赛一本通- P1547)(基础线段树和单点修改区间查询树状数组模版)
数据结构·算法·线段树·树状数组·单点修改 区间查询
罗湖老棍子2 个月前
简单题(信息学奥赛一本通- P1539)
数据结构·算法·树状数组·区间修改 单点查询
罗湖老棍子2 个月前
打鼹鼠_二维树状数组(信息学奥赛一本通- P1540)(二维树状数组模版题)
数据结构·算法·树状数组·二维树状数组
罗湖老棍子2 个月前
【例 1】数列操作(信息学奥赛一本通- P1535)
数据结构·算法·树状数组·单点修改 区间查询
Darkwanderor2 个月前
数据结构——树状数组和在线、离线操作
数据结构·c++·树状数组·离线操作
罗湖老棍子2 个月前
【例 3】校门外的树(信息学奥赛一本通- P1537)
数据结构·算法·树状数组
罗湖老棍子2 个月前
【例 2】数星星 Stars(信息学奥赛一本通- P1536)
数据结构·算法·树状数组·单点修改 区间查询
Jasmine_llq4 个月前
《P5445 [APIO2019] 路灯》
树状数组·树套树(树状数组套线段树)·二维单点更新 / 前缀查询·set 维护极长连通块·动态合并/分裂/连通性判断·二维差分(矩形更新转单点更新)·线段树加有序集合