pku2352: Stars
pku2352: http://poj.org/problem?id=2352
题意:给出星星的坐标,问每一层次n有多少个星星:星星a的左边或下边共有x个星星,则a属于层次x,ans[x]++,求ans[0]~ans[n-1]
解法1:线段树:从给出的坐标的顺序可知后面的坐标不会影响的前面的坐标,所以可以边输入边计算。首先建树,再从点1开始往下搜,若所求点d在树的左子树,继续往下搜,若在树的右子树,加上左子树的数目(左子树的点都小于d),再搜右子树,遇到左端点a与右端点b相同的情况,此时a=b=d,更新点,加一。
code1:
#include<iostream> #include<cstdio> #include<cstdlib> struct abc { int l,r,cnt; }v[33000*4]; int ans[16000]; void build(int s,int t,int k) //建树 { v[k].l=s; v[k].r=t; v[k].cnt=0; if(s==t) return; int mid=(s+t)/2; build(s,mid,k*2); build(mid+1,t,k*2+1); } int solve(int d,int k) { if(v[k].l==v[k].r) //l=r=d return ++v[k].cnt; //更新点 else { int x=0; if(d<=v[k*2].r) x=solve(d,k*2); else x=v[k*2].cnt+solve(d,k*2+1); v[k].cnt=v[k*2].cnt+v[k*2+1].cnt; //点往上更新 return x; //返回所求点左下点以及本身点的个数 } } int main() { int n,x,y; while(scanf("%d",&n)!=EOF) { memset(ans,0,sizeof(ans)); build(0,32000,1); for(int i=0;i<n;i++) { scanf("%d%d",&x,&y); ans[solve(x,1)-1]++; } for(int i=0;i<n;i++) printf("%d\n",ans[i]); } } /*input: 5 1 1 5 1 7 1 3 3 5 5 output: 1 2 1 1 0*/
解法2:树状数组:对于节点i,其父节点为i+i&(-i),其前一棵树为i-i&(-i),先初始化每个点为0,再求前x项和即可
code2:
#include<iostream> #include<cstdio> #include<cstdlib> int ans[32010],v[32010]; int lowbit(int x) //求最小幂2^k { return x&(-x); } int sum(int x) //求前n项和 { int s=0; while(x>0) { s=s+v[x]; x=x-lowbit(x); } return s; } void update(int x) //对某个元素进行加法操作 { while(x<32010) { v[x]++; x=x+lowbit(x); } } int main() { int n,x,y; while(scanf("%d",&n)!=EOF) { memset(ans,0,sizeof(ans)); memset(v,0,sizeof(v)); for(int i=0;i<n;i++) { scanf("%d%d",&x,&y); ans[sum(x+1)]++; //树状数组是从1开始的 update(x+1); } for(int i=0;i<n;i++) printf("%d\n",ans[i]); } } /*input: 5 1 1 5 1 7 1 3 3 5 5 output: 1 2 1 1 0*/