(POJ 2481)Cows 树状数组

来源:互联网 发布:怎么改变网络节点 编辑:程序博客网 时间:2024/05/23 00:26

Cows
Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 18570 Accepted: 6246
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.
Source

POJ Contest,Author:Mathematica@ZSU

题意:
有n个区间,每个区间由两个变量s,e表示,s为区间的开始点坐标,e为区间的结束点坐标,对于两个区间i,j, 若si <= sj && ei >= ej && ei - si > ej - sj ,那么就说区间i比区间j强。问你对于每一个区间有多少个区间比他强。

分析:
对于区间i比区间j强的定义,其实就是说区间j是区间i的一个真子集。

由于最简单想到的O(n^2)的算法是超时的,所以我们要用树状数组来优化

使用树状数组,所以我们要使得强的区间要先出现,因此我们要将区间进行排序,使s小的排在前面,s相等的e大的排在前面,那么就可以满足对于第n个区间而言,比他强的区间一定在他的前面,并且前面区间e值比第n个区间的e值大就满足强的条件了。(对于e值相等情况要特殊处理)

所以我们只需要用e值来维护树状数组了,每次我们用getsum(e-1)函数,就可以得到前面的比当前区间e值小的区间的个数m了,那么用当前的区间数减去m,就是比当前区间强的区间的个数了。

注意:
有两种特殊情况要特殊处理:
1:s == 0 && e == 0的情况。因为树状数组处理e=0的情况时会陷入死循环,所以我们不在树状数组中维护e==0 的情况。对于 0 0 的区间,比他强的区间一定是 0 x (x > 0)的区间,所以我们提前处理出0 x区间的个数m,那么所有的0 0 区间的答案就是m了。

2:由于我们没有用e== 0 的情况维护树状数组,假设0 0 的区间的个数为m1,那么处理后面的所以的区间的时候,要再减去m1。具体请看代码上的说明。

AC代码:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int maxn = 100010;struct node{    int s,e,pos;}nodes[maxn];int n,c[maxn];int ans[maxn];int lowbit(int x){    return x & (-x);}void update(int x){    while(x <= n)    {        c[x]++;        x += lowbit(x);    }}int getsum(int x){    int sum = 0;    while(x > 0)    {        sum += c[x];        x -= lowbit(x);    }    return sum;}int cmp(node a,node b){    if(a.s < b.s) return 1;    else if(a.s == b.s && a.e > b.e) return 1;    return 0;}int main(){    while(scanf("%d",&n)!=EOF && n)    {        memset(c,0,sizeof(c));        memset(ans,0,sizeof(ans));        for(int i=0;i<n;i++)        {            scanf("%d%d",&nodes[i].s,&nodes[i].e);            nodes[i].pos = i;        }        sort(nodes,nodes+n,cmp);        int m = 0; //记录0 x (x > 0) 的个数        int m1 = 0; //记录 0 0 的个数        for(int i=0;i<n;i++) if(nodes[i].s == 0 && nodes[i].e > 0) m++;        for(int i=0;i<n;i++)        {            if(nodes[i].s ==0 && nodes[i].e == 0)   // 处理0 0 的情况            {                ans[nodes[i].pos] = m;                m1++;                continue;            }            if(i > 0 && nodes[i].s == nodes[i-1].s && nodes[i].e == nodes[i-1].e)  //处理相同区间的情况            {                ans[nodes[i].pos] = ans[nodes[i-1].pos];                update(nodes[i].e);                continue;            }            int t = i - getsum(nodes[i].e - 1) - m1;   //前面的区间的个数 - e比当前e小的个数 - 0 0 情况的个数            ans[nodes[i].pos] = t;            update(nodes[i].e);        }        printf("%d",ans[0]);        for(int i=1;i<n;i++)            printf(" %d",ans[i]);        printf("\n");    }    return 0;}
1 0