poj2481~Cows~(树状数组)
原创
©著作权归作者所有:来自51CTO博客作者breakDawn的原创作品,请联系作者获取转载授权,否则将追究法律责任

题意:一群区间,问你对于每个区间,他被多少个区间覆盖?例如2-4就是被1-5覆盖的,但是需要区间长度不能相等,例如2-4是被2-5覆盖,但是不被2-4覆盖。
思路:树状数组。继续直接用例子来讲思路吧。
样例:
4
1 3
1 3
4 5
4 6
2 6
首先,我会将以区间的终点为依据进行降序排序,如果终点相等就对起点升序排序,排完后就变成了这样:
终点:6 6 5 3 3
起点:2 4 4 1 1
序号:1 2 3 4 5
好,看第一个区间,肯定没有区间能覆盖他,因为他的终点是最大的,起点又是最小的。 然后将起点2插入树状数组c,表示2处有一个点
看第二个区间,它的起点是4,通过sum函数,判断出4前面有一个点,说明有一个区间覆盖了它,保存进ans数组。然后再将4插入树状数组c
继续看第三个区间,起点也是4,通过sum函数判断出4前面有2个点(包括4)。
同理第四个
第五个就有点特别了,1 3和1 3是一样的,所以他们的结果应该是一样的,而不是+1,所以直接赋予和它一样的答案。
具体实现过程请看代码。详细的注释哦
#include<iostream>
#include<string>
#include<algorithm>
#define M 100005
using namespace std;
int c[M],n,ans[M];
struct COW
{
int s,e,num;
};
COW cow[M];
int cmp(struct COW &a,struct COW &b)
{
if(a.e>b.e)
return 1;
else if(a.e==b.e) //如果终点相同,比较起点,让起点小的在前面
{
if(a.s<b.s)
return 1;
else return 0;
}
else return 0;
}
int sum(int i) //查询0到i区间的数值状况
{
int s=0;
while(i>0)
{
s+=c[i];
i-=i&(-i);
}
return s;
}
void update(int i,int value)//更新i点的数值状况
{
while(i<=n)
{
c[i]+=value;
i+=i&(-i);
}
}
int main()
{
int i,j;
while(scanf("%d",&n),n!=0)
{
for(i=1;i<=n;i++)
{
scanf("%d%d",&cow[i].s,&cow[i].e);
cow[i].num=i; //记录原来的序号,因为要按原顺序输出答案
cow[i].s++;cow[i].e++;//好像我上面那个update函数中i为0的话会有问题,就每个加一了
}
sort(cow+1,cow+1+n,cmp); //对终点进行降序排序
memset(c,0,sizeof(c)); //初始化
for(i=1;i<=n;i++)
{
if(cow[i].s==cow[i-1].s&&cow[i].e==cow[i-1].e) //排除了区间相等的情况
ans[cow[i].num]=ans[cow[i-1].num];
else
ans[cow[i].num]=sum(cow[i].s); //ans=0到s之间的点的个数
update(cow[i].s,1); //更新
}
for(i=1;i<=n;i++) //注意输出格式
{
printf("%d",ans[i]);
if(i!=n) printf(" ");
else printf("\n");
}
}
return 0;
}