您的位置:首页 > 其它

poj 2481 Cows 树状数组+逆序对变形

2016-10-07 21:05 337 查看
题目:

Cows

Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 17073 Accepted: 5729
Description

Farmer John's cows have discovered that the clover growing along the ridge of the hill (which we can think of as a one-dimensional number line) in his field is particularly good. 

Farmer John has N cows (we number the cows from 1 to N). Each of Farmer John's N cows has a range of clover that she particularly likes (these ranges might overlap). The ranges are defined by a closed interval [S,E]. 

But some cows are strong and some are weak. Given two cows: cowi and cowj, their favourite clover range is [Si, Ei] and [Sj, Ej]. If Si <= Sj and Ej <= Ei and Ei - Si > Ej - Sj, we say that cowi is stronger than cowj. 

For each cow, how many cows are stronger than her? Farmer John needs your help!
Input

The input contains multiple test cases. 

For each test case, the first line is an integer N (1 <= N <= 105), which is the number of cows. Then come N lines, the i-th of which contains two integers: S and E(0 <= S < E <= 105) specifying the start end location respectively of a
range preferred by some cow. Locations are given as distance from the start of the ridge. 

The end of the input contains a single 0.
Output

For each test case, output one line containing n space-separated integers, the i-th of which specifying the number of cows that are stronger than cowi. 

Sample Input
3
1 2
0 3
3 4
0

Sample Output
1 0 0

Hint

Huge input and output,scanf and printf is recommended.

给定一些区间,对于每一段区间求比它大的区间数。一个区间比另一个区间大定义为大区间完全包含小区间且长度比小区间长。

分析:

数据量大,暴力O(N^2)算法会超时。区间左右端点都是不固定的,如果固定了一端,那么只需要考虑另一端的情况,问题得以简化。固定一端可以通过排序实现。如果优先保证对于一个区间排序后它前面的都是区间右值大于它的,那么只需要在这些区间里面找有几个左值更小或者相等的。排序之后的查找统计操作可以通过树状数组高效实现。查好之后保存在数组里再按序输出就可以了。

需要留意的是本题树状数组的大小应该是所需要维护的左值或右值中的最大值,而不是区间数n。另外为了避免意想不到的bug,树状数组一般用下标为1到n的空间来存储数据,本题中输入的左右值有可能为零,所以每次读取时需要加一。

代码:

#include<iostream>//poj2481 左上角
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=100010;

struct node{
int s;
int e;
int id;
}a[maxn];

int n,c[maxn],bound;
__int64 cnt[maxn];

bool cmp(node a,node b){ //先保证排序后前面的都是区间左值大的
if(a.e==b.e) return a.s<b.s;
else return a.e>b.e;
}

__int64 sum(int i){
__int64 s=0;
while(i>0){
s+=c[i];
i-=i&(-i);
}
return s;
}

void add(int i,int x){
while(i<=bound){		//i<=什么每次要考虑清楚
c[i]+=x;
i+=i&(-i);
}
}

int main(){
int x,y;
while(~scanf("%d",&n),n){
bound=0;
for(int i=1;i<=n;++i){
scanf("%d%d",&x,&y);
a[i].s=x+1;
a[i].e=y+1;
bound=max(a[i].s+1,bound);
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
memset(c,0,sizeof(c));
memset(cnt,0,sizeof(cnt));
cnt[a[1].id]=0;//没有比它更强壮的
add(a[1].s,1);
for(int i=2;i<=n;++i){
if(a[i].e==a[i-1].e&&a[i].s==a[i-1].s) cnt[a[i].id]=cnt[a[i-1].id];//所有相同区间都应该取这些区间都不算时的值
else cnt[a[i].id]=sum(a[i].s);
add(a[i].s,1);//后添加 自己不算
}
for(int i=1;i<n;++i){
printf("%I64d ",cnt[i]);
}
printf("%I64d\n",cnt
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: