树状数组例题-数星星,简单题easy,校门外的树2,清点人数
【例1】数星星
天空中有一些星星,这些星星都在不同的位置,每个星星都有个坐标,如果一个星星的左下方(包括正左和正下)有k颗星星,就说这颗星星是k级的。
比如,上图中,星星5是3级的(1,2,4在其左下方)
2,4是1级的。
给定星星的位置,输出各级星星的数目。
简述:先按y坐标来排序,就用x来作为参考用树状数组来求解答案(前缀和)
代码
#include<iostream> #include<cstdio> using namespace std; const int MAXN=20005; const int MAXX=40005; struct node{ int x,y; }p[MAXN]; int n,m=MAXX,c[MAXX],ans[MAXX]; int lowbit(int x){ return x&(-x); } void update(int x,int y){ while(x<=m)c[x]+=y,x+=lowbit(x); } int sum(int x){ int tot=0; while(x){ tot+=c[x]; x-=lowbit(x); } return tot; } int main(){ cin>>n; for(int i=1;i<=n;++i)cin>>p[i].x>>p[i].y; for(int i=1;i<=n;++i){ int u=p[i].x+1; int v=sum(u); update(u,1); ans[v]++; } for(int i=0;i<n;++i)cout<<ans[i]<<endl; }
【例2】校门外的树2
校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:K=1,K=1,读入l、r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同K=2,读入l,r表示询问l~r之间能见到多少种树(l,r>0)
简述:这题不能用暴力的方法。所以我们将线段看成括号序列(即左右打上标记,由此就是范围内有一种树),再用前缀和求解。
#include<iostream> #include<cstdio> using namespace std; const int MAXN=2000005; int n,c_1[MAXN],m,c_2[MAXN]; inline int lowbit(int x){ return x&(-x); } void update_1(int x,int y){ for(;x<=n;x+=lowbit(x))c_1[x]+=y; } void update_2(int x,int y){ for(;x<=n;x+=lowbit(x))c_2[x]+=y; } int sum_1(int x){ int res=0; for(;x;x-=lowbit(x))res+=c_1[x]; return res; } int sum_2(int x){ int res=0; for(;x;x-=lowbit(x))res+=c_2[x]; return res; } int main(){ cin>>n>>m; for(int i=1;i<=m;++i){ int k,l,r; cin>>k>>l>>r; if(k==1)update_1(l,1),update_2(r,1); else printf("%d ",sum_1(r)-sum_2(l-1)); } }