HDU 1556 线段树或树状数组,插段求点
Posted 掉血菜鸡煮熟中
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 1556 线段树或树状数组,插段求点相关的知识,希望对你有一定的参考价值。
1、HDU 1556 Color the ball 区间更新,单点查询
2、题意:n个气球,每次给(a,b)区间的气球涂一次色,问最后每个气球各涂了几次。
(1)树状数组
总结:树状数组是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值。
这里改下思路可以用树状数组。在更新(a,b)时,向上更新,将a~n加1,b+1~n减1。查询点时,向下求和即可。
#include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define F(i,a,b) for (int i=a;i<b;i++) #define FF(i,a,b) for (int i=a;i<=b;i++) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define LL long long using namespace std; const int N=10010,MAX=100100; int n,c[MAX]; int lowbit(int x) { //计算2^k return x&-x; } void update(int x,int val) { //向上更新,使所有包含了x的区间都更新一下 while(x<=n) { c[x]+=val; x+=lowbit(x); } } int Sum(int x) { //向下查询 int sum=0; while(x>0) { sum+=c[x]; x-=lowbit(x); } return sum; } int main() { while(~scanf("%d",&n),n) { mes(c,0); int a,b; FF(i,1,n) { scanf("%d%d",&a,&b); update(a,1); update(b+1,-1); } F(i,1,n) printf("%d ",Sum(i)); printf("%d\\n",Sum(n)); } return 0; }
(2)线段树+lazy思想
总结:lazy,更新时只到区间,可以节省很多时间。
#include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define F(i,a,b) for (int i=a;i<b;i++) #define FF(i,a,b) for (int i=a;i<=b;i++) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define LL long long using namespace std; const int N=10010,MAX=100010; int n,c[MAX<<2]; void build(int o,int L,int R) { c[o]=0; if(L==R) return ; int mid=(L+R)>>1; build(o<<1,L,mid); build(o<<1|1,mid+1,R); } void update(int o,int l,int r,int L,int R) { if(l<=L&&R<=r) { c[o]++; return ; } //关键:只更新到区间,一开始更新到每个单独的点,果断T了,//然后用l==L&&R==r,又果断MLE int mid=(L+R)>>1; if(mid<l) update(o<<1|1,l,r,mid+1,R); else if(r<=mid) update(o<<1,l,r,L,mid); else { update(o<<1,l,r,L,mid); update(o<<1|1,l,r,mid+1,R); } } int ans[MAX]; void query(int o,int L,int R) { if(c[o]) { for(int i=L; i<=R; i++) ans[i]+=c[o]; //也是lazy思想,标记了的区间就加上 } if(L==R) return ; //询问时还是要到点 int mid=(L+R)>>1; query(o<<1,L,mid); query(o<<1|1,mid+1,R); } int main() { while(~scanf("%d",&n) ,n ) { build(1,1,n); fill(ans+1,ans+1+n,0); //fil函数 int a,b; FF(i,1,n) { scanf("%d%d",&a,&b); update(1,a,b,1,n); } query(1,1,n); F(i,1,n) printf("%d ",ans[i]); printf("%d\\n",ans[n]); } return 0; }
以上是关于HDU 1556 线段树或树状数组,插段求点的主要内容,如果未能解决你的问题,请参考以下文章
HDU - 1556 Color the ball(线段树和树状数组)