小记:之前没做什么修改之前,在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;
}