poj2481~Cows~(树状数组)_#include

题意:一群区间,问你对于每个区间,他被多少个区间覆盖?例如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;
}