首页 > 代码库 > 线段树
线段树
线段树是一个碉炸的数据结构,有多碉炸呢?可以看一下zkw大神的《统计的力量》,里面是讲zkw树的,不用看懂,就了解一下线段树有多碉炸就行。
看我把它撸过来:
然后我们来学一下线段树。
线段树一般是怒存在数组里的,一般a[1]是根节点,然后a[i]的左儿子是a[i<<1] (i<<1是位运算向左移1位,相当于乘2),右儿子是a[i<<1 | 1],爸是a[i>>1]。
根据这个规律,我们可以用递归来用线段树处理点、区间问题。
线段树一般有几个函数,build初始化线段树,update对线段树进行修改,query对线段树进行查询。然后里面用到PushUp和PushDown,分别是从当前节点的儿子收集信息传给当前节点、把当前节点的信息传下去给儿子,有时只用其中的一个,有时两个都用。
最简单的是单点修改、区间求和。修改的容易,自顶向下递归找到那个要改的点,改一发。区间求和要求单点修改的时候就计算好区间的和,回溯的时候PushUp传递上去。
我的代码都是参照http://www.notonlysuccess.com/index.php/segment-tree-complete/写的,比较好懂,推荐大家看他的碉代码。
例1.敌兵布阵
单点加减,区间求和。
1 #include<cstdio> 2 #include<cmath> 3 #include<iostream> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #include<map> 8 #include<set> 9 #include<stack>10 #include<queue>11 using namespace std;12 #define ll __int6413 #define usint unsigned int14 #define mz(array) memset(array, 0, sizeof(array))15 #define minf(array) memset(array, 0x3f, sizeof(array))16 #define REP(i,n) for(int i=0;i<(n);i++)17 #define FOR(i,x,n) for(int i=(x);i<=(n);i++)18 #define RD(x) scanf("%d",&x)19 #define RD2(x,y) scanf("%d%d",&x,&y)20 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)21 #define WN(x) printf("%d\n",x);22 #define RE freopen("D.in","r",stdin)23 #define WE freopen("1.out","w",stdout)24 25 #define lson l,m,rt<<126 #define rson m+1,r,rt<<1|127 const int maxn=51111;28 int a[maxn<<2];29 30 void PushUP(int rt){31 a[rt]=a[rt<<1]+a[rt<<1|1];32 }33 34 void build(int l,int r,int rt){35 if(l==r){36 scanf("%d",&a[rt]);37 return;38 }39 int m=(l+r)>>1;40 build(lson);41 build(rson);42 PushUP(rt);43 }44 45 void update(int p,int add,int l,int r,int rt){46 if(l==r){47 a[rt]+=add;48 return;49 }50 int m=(l+r)>>1;51 if(p<=m)update(p,add,lson);52 else update(p,add,rson);53 PushUP(rt);54 }55 56 int query(int L,int R,int l,int r,int rt){57 if(L<=l&&r<=R){58 return a[rt];59 }60 int m=(l+r)>>1;61 int ret=0;62 if(L<=m)ret+=query(L,R,lson);63 if(R>m)ret+=query(L,R,rson);64 return ret;65 }66 67 int main()68 {69 int cas=1,T;70 char s[10];71 int x,y,i,n;72 scanf("%d",&T);73 while(T--)74 {75 scanf("%d",&n);76 build(1,n,1);77 printf("Case %d:\n",cas++);78 while(scanf("%s",s)!=EOF){79 if(s[0]==‘E‘)break;80 scanf("%d%d",&x,&y);81 if(s[0]==‘A‘) update(x,y,1,n,1);///x地增加y人82 else if(s[0]==‘S‘)update(x,-y,1,n,1);///x地减少y人83 else if(s[0]==‘Q‘)printf("%d\n",query(x,y,1,n,1));///x~y总人数84 }85 }86 return 0;87 }
例2.
(未完待续)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。