poj2481 Cows

Cows

Time Limit: 3000MSMemory Limit: 65536K
Total Submissions: 20652Accepted: 7019

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: cow i and cow j, their favourite clover range is [Si, Ei] and [Sj, Ej]. If Si <= Sj and Ej <= Ei and Ei - Si > Ej - Sj, we say that cow i is stronger than cow j.

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 <= 10 5), which is the number of cows. Then come N lines, the i-th of which contains two integers: S and E(0 <= S < E <= 10 5) 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 cow i.

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.

题目描述

这是一道树状数组题目,如果对树状数组不太熟悉,可以参考树状数组
对于cow_i对应一个区间[S_i,E_i],对于cow_i和cow_j如果满足S_i≤S_j and E_i≥E_j,则称cow_i比cow_j强壮,对于一个给定的cow_i,给出共有多少个比cow_i强壮的牛。

算法设计

首先需要明确一点,这个题目是离线的而不是在线的,所以一开始对于输入进行排序,排序之前需要记录该牛的编号,所以对于该牛可以使用以下结构进行储存,并重写比较函数。

struct cow{
    int s,e,position;
    bool operator <(const cow a){
        if(a.e == e){
            return a.s > s;
        }
        else{
            return a.e < e;
        }
    }
}

排序完成后可以根据排序来进行统计,如果排序之后的牛与前面相邻的牛具有相同的[S_i,E_i],则直接记前面相邻牛对应的数量即可,否则使用sum函数进行统计,每次都需要使用update进行更新,直到遍历完成,此时即可获得所有的比任意一个牛强壮的牛的数量。伪代码如下:

for i = 1 to n
    if(input[i].e == input[i-1].e && input[i].s == input[i-1].s){
        res[input[i].position] = res[input[i-1].position];
    }
    else{
        res[input[i].position] = sum(input[i].s+1);
    }
    update(input[i].s+1,1);

代码实现

#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAX = 100010;
int BIT[MAX],res[MAX];
int lowBit(int i);
void update(int index,int delta);
int sum(int index);
struct cow{
    int s,e,position;
    bool operator <(const cow a){
        if(a.e == e){
            return a.s > s;
        }
        else{
            return a.e < e;
        }
    }
}input[MAX];
int main(){
    int n;
    while(scanf("%d",&n)){
        if(n == 0){
            break;
        }
        memset(BIT,0,sizeof(BIT));
        memset(res,0,sizeof(res));
        for(int i = 1;i <= n;i ++){
            scanf("%d%d",&input[i].s,&input[i].e);
            input[i].position = i;
        }
        sort(input+1,input+n+1);
        for(int i = 1;i <= n;i ++){
            if(input[i].e == input[i-1].e && input[i].s == input[i-1].s){
                res[input[i].position] = res[input[i-1].position];
            }
            else{
                res[input[i].position] = sum(input[i].s+1);
            }
            update(input[i].s+1,1);
        }
        for(int i = 1;i <= n;i ++){
            if(i == n){
                printf("%d\n",res[i]);
            }
            else{
                printf("%d ",res[i]);
            }
        }
    }
    return 0;
}
int lowBit(int i){
    return i & (-i);
}
int sum(int index){
    int res = 0;
    for(int i = index;i > 0;i -= lowBit(i)){
        res += BIT[i];
    }
    return res;
}
void update(int index,int delta){
    for(int i = index;i <= MAX;i += lowBit(i)){
        BIT[i] += delta;
    }
}

复杂度分析

初始化输入时间复杂度为O(n),对每一个元素进行查询每一次为O(log⁡〖n)〗,一共n次,所以时间复杂度为(O(n log⁡〖n)〗,由于只是增添了一个辅助数组,所以空间复杂度仍为O(n)。

编程技巧

本问题仍不能直接使用序号进行区间查询,所以还是需要建立一个序号到支持区间查询序号之间的一对一映射来完成该操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值