题目链接:http://poj.org/problem?id=2481
题目大意:
1 题目给定n头牛所在的区间,然后问每头牛都有几头牛比它强壮
2 根据题目如果牛i的区间是[Si , Ei],牛j的区间是[Sj , Ej]那么牛i要比牛j强壮的话那么就有Si <= Sj && Ei >= Ej && Si-Ei != Sj-Ej;
思路:
一:总体的思路
先对每个牛排序,然后对每头牛查找比他的力量大的牛的个数
二:牛的排序
struct node
{
int s,e;
int number;
bool operator <(const node &tmp)const
{
//按照左边界的顺序排序 当左边界相同时 力量大的在前 即右边界大的在前
if(s!=tmp.s)
return s<tmp.s;
else
return e>tmp.e;
}
bool operator ==(const node &tmp)const
{
return s==tmp.s&&e==tmp.e;
}
}nodes[MAXN];
因为我们之后是对每头牛查找力量比他的牛,所以先按照左边界的顺序排序 ,即保证之前牛的左边界一定比他小,即在他之后的牛一定不可能力量比他的,比他力量大的牛只可能在之前,所以当左边界相同时 ,也需要力量大的在前 ,即右边界大的在前.
还有需要注意的是:
ans[nodes[i].number]+=i-getSum(id-1);
因getsun求得是【1,x】而不是【x,maxn)所以,转化为之前的个数减去小于他的个数。
为什么是小于他的个数,即为什么是id-1?
因为他左边界已经不同,即使右边界相同,力量也会比他大!!
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN =100010;
struct node
{
int s,e;
int number;
bool operator <(const node &tmp)const
{
//按照左边界的顺序排序 当左边界相同时 力量大的在前 即右边界大的在前
if(s!=tmp.s)
return s<tmp.s;
else
return e>tmp.e;
}
bool operator ==(const node &tmp)const
{
return s==tmp.s&&e==tmp.e;
}
}nodes[MAXN];
int n;
int ans[MAXN];
int treenum[MAXN];
int lowbit(int x){
return x&(-x);
}
int getSum(int x){//一维
int sum = 0;
while(x){//将以x为根节点的数 相当于求其叶节点的和 但其非叶节点等于其两个子节点的和
sum += treenum[x];
x -= lowbit(x);
}
return sum;
}
void add(int x , int val){//一维
while(x < MAXN){//相当于一个树 他将其自己以及他的父节点一路向上都加val
treenum[x] += val;
x += lowbit(x);
}
}
void solve()
{
memset(ans,0,sizeof ans);
memset(treenum,0,sizeof treenum);
sort(nodes,nodes+n);
for(int i=0;i<n;i++)
{
int id=nodes[i].e;
if(i&&nodes[i]==nodes[i-1])
ans[nodes[i].number]=ans[nodes[i-1].number];
else
{
ans[nodes[i].number]+=i-getSum(id-1);//为什么要id-1? 因为他是之前的个数减去小于他的个数,即求大于等于他的个数
// 他左边界已经不同 右边界可以相同
}
add(id,1);
}
printf("%d" , ans[0]);
for(int i = 1 ; i < n ; i++)
printf(" %d" , ans[i]);
printf("\n");
}
int main(){
while(~scanf("%d",&n)&&n)
{
for(int i=0;i<n;i++)
{
scanf("%d%d",&nodes[i].s,&nodes[i].e);
nodes[i].number=i;
}
solve();
}
return 0;
}