poj 2481 Cows (树状数组)

小记:之前没做什么修改之前,在poj上提交1393MS AC了。然后在hdu的web diy里提交gnu c++ 超时了、于是不断的改,在输出的地方花费时间太多了。就是为了保证每两个数之间有一个空格,然后末尾没有空格,我在for里面加了一个判断,只要不是末尾就输出一个空格。然后就这样超时了。。 树状数组全用了inline。 改了一下输出之后。poj969MS,hdu web diy 2250MS 都AC了


思路:树状数组的应用的难点就是你要在哪里用树状数组,使得结果是你要的答案。

这里我是对输入的区间先全部存入一个结构体数组,结构体保存每个区间的左右值(L,R),以及输入的次序(id)。

然后对该结构体数组以x坐标从大到小,如果x坐标想等,以y坐标从小到大的顺序排,

inline bool  cmp1(const node& a,const node& b){
    if(a.L == b.L)return a.R < b.R;
    return a.L > b.L;
}

这样做的原因是,我们等下就可以从排好序的数组的最后一个开始算起,对y用树状数组,求得它前面大于等于它的y的数的个数(这里的前面指的是在它前面算过的的数),

ans[a[k].id] = T - 1 - k - sum(a[k].R);

如果当前区间和前面的一个区间是相同的,那么它的结果就是前面的区间的计算结果,

if(k+1<T && a[k].R == a[k+1].R && a[k].L == a[k+1].L){
      ans[a[k].id] = ans[a[k+1].id];
}

算出来的这个值就是这个区间的answer。


 因为x从小到大,那么就保证了越前面的x越 大,越后面的x越小,我们从最后一个算起,那么只要不是和前面区间相同,那么之前算过的区间中y值大于等于它的区间就都是符合比它牛的条件的。

例如:

1 2

0 3

3 4

排好序后:

3 4

1 2

0 3

从0 3开始算起,3前面没有大于等于它的数,所以0 3的答案是0, 

然后1 2,2前面有个大于它的3,所以1 2的答案是1,

然后3 4,4前面算过的没有大于等于它的数,所以3 4 的答案是0,

用id存入,输出的答案就是1 0 0


因此保证了算法的正确性。


代码:

#include <stdio.h>
#include <algorithm>
#include <string.h>

#define mst(a,b) memset(a,b,sizeof(a))

#define MAX_ 100010
#define MAX 100010


struct node{
    int L, R, id;
}a[MAX_];

int C[MAX_], ans[MAX_];

inline int  lowbit(int x){return x&(-x);}

inline void  add(int x,int num){
    while(x < MAX){
        C[x] += num;
        x += lowbit(x);
    }
}

inline int  sum(int x){
    int cnt = 0;
    while(x > 0){
        cnt += C[x];
        x -= lowbit(x);
    }
    return cnt;
}


inline bool  cmp1(const node& a,const node& b){
    if(a.L == b.L)return a.R < b.R;
    return a.L > b.L;
}



int main(){
    int T, x, y, cnt, i, k, j;
    while(scanf("%d",&T),T){
        for(i = 0; i < T; ++i){
            scanf("%d%d",&x,&y);
            a[i].L = x + 1;
            a[i].R = y + 1;
            a[i].id = i;
        }
        std::sort(a,a+T,cmp1);
        mst(C,0);
        for( k = T-1; k > -1; --k){
            if(k+1<T && a[k].R == a[k+1].R && a[k].L == a[k+1].L){
                ans[a[k].id] = ans[a[k+1].id];
            }
            else
                ans[a[k].id] = T - 1 - k - sum(a[k].R);
            add(a[k].R+1,1);
        }

        for( i = 0; i < T-1; ++i){
            printf("%d ",ans[i]);
            //if(i!=T-1)printf(" ");
        }
        printf("%d\n",ans[T-1]);
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值