链接:https://ac.nowcoder.com/acm/contest/949/F
来源:牛客网
题目描述
小石有 n 个妹子,每个妹子都有一个细心程度 ai 和一个热心程度 bi,
小石想给她们一个重要程度 ti(重要程度为 1 表示最重要,重要程度越小表示越重要)。如果一个妹子 i 的细心程度和热心程度都比妹子 j 大,那么妹子 i 的重要程度要大于妹子 j 的重要程度,即妹子 i 比妹子 j 重要。
流程如下:
每次从所有没有重要程度的妹子中,找到若干妹子。对于这些妹子的任意一个,需要保证没有其他妹子比她更重要。然后把她们的重要程度标为 1 。下一次再从剩下没有重要程度的妹子中找到若干妹子,依然符合上述条件,然后把她们的重要程度标为 2,……,重复直到所有妹子都有自己的重要程度。
由于妹子太多,小石忙不过来,请你帮帮他。
输入描述:
第一行输入一个正整数 n,表示妹子的数量。
接下来 n 行,每行两个正整数 ai,bi,描述每个妹子的细心程度和热心程度。
保证所有的 ai 两两不等,所有的bi 两两不等。
输出描述:
共 n 行,第 i 行输出一个正整数 ti 表示第 i 个妹子的重要程度。
示例1
输入
5
1 4
2 2
3 3
4 1
5 5
输出
2
3
2
2
1
说明
第一轮取第 5 个妹子(5 5),因为没有其他妹子比她重要,标记为 1;
第二轮取编号为 1,3,4 的妹子,因为对于其中的任意一个妹子,都没有其他妹子比她们重要,标记为 2;
第三轮把编号为 2 的妹子标记为 3 。
备注:
1 ≤ n ≤ 105, 1 ≤ ai,bi ≤ 109
分析:
先按a从大到小排序,然后以此顺序进行排名,对于第 i 个女生,rk[i] = max{ rk[j] } + 1( b[j] > b[i] )
其中 max{ rk[j] } 即现有的其b[j] 比 b[i] 大的女生中最大的那个排名(即现有的最低排名),又因为是按a从大到小进行排名,所以max{ rk[j] } 里面的非0值都是a、b均比 a[i]、b[i]大的女生的排名,故要找最大的那个排名。
所以可以用线段树维护max,b[i]作为下标,rk[i]作为值,初始化线段树都为0,然后每次把新的排名往里面加 (单点更新)。但要注意先将b离散化处理一下。
以下代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<algorithm>
#define LL long long
#define PII pair<int,int>
using namespace std;
const int INF=0x3f3f3f3f;
const int MOD=1e9+7;
const int maxn=1e5+50;
int n;
struct node
{
int id;
int a;
int b;
}x[maxn];
bool cmp(const node &x,const node &y){ return x.a>y.a; }
void Hash()
{
int B[maxn];
for(int i=1;i<=n;i++)
B[i]=x[i].b;
sort(B+1,B+n+1);
for(int i=1;i<=n;i++) //无相同数据,无需unique()去重
x[i].b=lower_bound(B+1,B+n+1,x[i].b)-B;
}
int t[4*maxn];
void updata(int rt,int l,int r,int k,int num) //单点更新
{
if(l==r)
{
t[rt]=num;
return;
}
int mid=(l+r)>>1;
if(k<=mid)
updata(rt<<1,l,mid,k,num);
else
updata(rt<<1|1,mid+1,r,k,num);
t[rt]=max(t[rt<<1],t[rt<<1|1]);
}
int query(int rt,int l,int r,int ql,int qr) //区间查询
{
if(ql<=l&&r<=qr)
return t[rt];
if(r<ql||l>qr)
return 0;
int mid=(l+r)>>1;
return max(query(rt<<1,l,mid,ql,qr),query(rt<<1|1,mid+1,r,ql,qr));
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d %d",&x[i].a,&x[i].b);
x[i].id=i;
}
sort(x+1,x+n+1,cmp); //按a进行排序
Hash(); //离散化处理b
int rk[maxn];
memset(t,0,sizeof(t)); //线段树初始化为0
for(int i=1;i<=n;i++)
{
rk[x[i].id]=query(1,1,n,x[i].b,n)+1; //在比b[i]大的里面(b[i]~n)找最大的rk
updata(1,1,n,x[i].b,rk[x[i].id]); //更新最大值
}
for(int i=1;i<=n;i++)
printf("%d\n",rk[i]);
return 0;
}