链接:
http://poj.org/problem?id=2352
题目大意:
在坐标上有n个星星,如果某个星星坐标为(x, y), 它的左下位置为:(x0,y0),x0<=x 且y0<=y。如果左下位置有a个星星,就表示这个星星属于level x
按照y递增,如果y相同则x递增的顺序给出n个星星,求出所有level水平的数量。
思路:
由于输入的顺序,对于第i颗星星,它的等级是之前输入的星星中,横坐标x小于等于i星横坐标的那些星星的总数量(前面的y一定比后面的y小)。
所以是查询+更新操作
查询0~x 坐标的所有星星的和,再把x坐标的星星数加1
正好符合树状数组的用法,要注意,树状数组是对数列从坐标1开始的一列数,所以输入的时候把x++,因为树状数组用位运算实现,所以必须从1开始,否则会在代码中add操作中出现死循环
//312K 141MS #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 32005; const int N = 15005; #define lowbit(x) (x&(-x)) int tree[MAXN]; int ans[N]; int sum(int i) { int s=0; while(i>0){ s+=tree[i]; i-=lowbit(i); } return s; } void add(int i) { while(i<=MAXN-1){ //防止正好算出了MAXN,因为tree的下标最大也只有MAXN-1 tree[i]++; i+=lowbit(i); //i>0 否则死循环 } } int main() { int n; scanf("%d",&n); for(int i=0;i<n;i++){ int x,y; scanf("%d%d",&x,&y); ans[sum(++x)]++; add(x); } for(int i=0;i<n;i++) printf("%d\n",ans[i]); return 0; }
//984K 235MS #include<iostream> #include<cstdio> #include<cstring> using namespace std; #define LL(x) (x<<1) #define RR(x) (x<<1|1) #define MID(a,b) (a+((b-a)>>1) ) #define M 32222 struct node { int l,r; int sum; int mid(){return MID(l,r);} }; struct Segtree { node tree[M<<2]; void build(int l,int r,int rt) { tree[rt].l=l,tree[rt].r=r; if(l==r) return ; int m=tree[rt].mid(); build(l,m,LL(rt)); build(m+1,r,RR(rt)); } void up(int rt) { tree[rt].sum=tree[LL(rt)].sum+tree[RR(rt)].sum; } void update(int rt,int pos) { if(tree[rt].l==tree[rt].r){ tree[rt].sum++; return; } int m=tree[rt].mid(); if(pos<=m) update(LL(rt),pos); else update(RR(rt),pos); up(rt); } int query(int st,int ed,int rt) { if(st>tree[rt].r||ed<tree[rt].l) return 0; if(st<=tree[rt].l&&tree[rt].r<=ed){ return tree[rt].sum; } return query(st,ed,LL(rt))+query(st,ed,RR(rt)); } }seg; int main() { int n; int ans[20000]; seg.build(0,32000,1); scanf("%d",&n); memset(ans,0,sizeof(ans)); for(int i=0; i<n; i++) { int x,y; scanf("%d%d",&x,&y); ans[seg.query(0,x,1)]++; seg.update(1,x); } for(int i=0; i<n; i++) printf("%d\n",ans[i]); return 0; }