在Alibaba上碰到了中级的线段树问题,另外在队内集训的时候做2010年的多校联合的题时,遇到了两道线段树。
但是无奈的我只会树状数组。如果用树状数组来段更新,简直是以卵击石嘛~
接连受打击,无奈之下只好拜读了下Roba,NOS的博客,他们的教学博客写得很好。
简直是膜拜了~~~
鄙人无奈的弱菜啊~~
线段树基于二叉查询数,通过手动judge可以知道其美妙的结构~
网络上很多的树形图都是错的。
(1,6) 1
/ \ / \
(1,3) (4,6) 2 3
/ \ / \ / \ / \
(1,2) (3,3) ( 4,5) (6,6) 4 5 6 7
/ \ / \ / \ / \
(1,1) (2,2) (4,4) (5,5) 8 9 12 13
上面左图数线段树,右图是每个节点在一维数组中对应的标号。
学过数据结构的同学应该知道二叉树的原理
同样在线段树中也能这样。
每个根节点的左子树标号=当前根节点标号<<1;
每个根节点的右子树标号=当前根节点标号<<1|1;
对于构建二叉树用递归就行了。
稍微理解一下二叉树,对于线段树就很好写了。
当然我写得是最最简单最最基础的线段树,一句话 弱爆了!
#include<stdio.h> #include<string.h> #define MAXN 2000001 int sum[MAXN]; void PushUp( int root ){ sum[root]=sum[root<<1]+sum[root<<1|1]; } void build( int l,int r,int root ) { if( l==r ) { scanf( "%d",&sum[root] ); return ; } int m=(l+r)/2; build( l,m,root<<1 ); build( m+1,r,root<<1|1 ); PushUp(root); } void update( int at,int value,int L,int R,int root ) { if( L==R ){ sum[root]+=value;return ; } int m=(L+R)/2; if( at<=m )update(at,value,L,m,root<<1 ); else update( at,value,m+1,R,root<<1|1 ); PushUp( root ); } int query( int l,int r,int L,int R,int root ) { int res=0; if( l<=L && R<=r ) return sum[root]; int m=(L+R)/2; if( l<=m ) res+=query( l,r,L,m,root<<1 ); if( m<r ) res+=query( l,r,m+1,R,root<<1|1 ); return res; } int main() { int loop,a,b,c; char com[100]; int index=1; scanf( "%d",&loop ); while( loop-- ) { int i,j,n; scanf( "%d",&n ); build(1,n,1); printf( "Case %d:\n",index++ ); while( scanf( "%s",com ) ) { if( com[0]=='E' ) break; scanf( "%d%d",&a,&b ); if( com[0]=='Q' ) printf( "%d\n",query(a,b,1,n,1) ); else if( com[0]=='A' ) update( a,b,1,n,1 ); else update( a,-b,1,n,1 ); } } return 0; }