标签:
线段树主要用于区间记录信息(如区间和、最大最小值等),首先是建树:
这里以求和为例:
1 const int MAXM=50000; //定义 MAXM 为线段最大长度
2
3 int a[MAXM+5],segtree[(MAXM<<2)+5]; // a 数组为 main 函数中读入的内容,segtree 数组为需要查询的数的信息(如和、最值等),树的空间大小为线段最大长度的四倍
4
5 void build(int o,int l,int r){ //传入的参数为 o:当前需要建立的结点;l:当前需要建立的左端点;r:当前需要建立的右端点
6 if(l==r)segtree[o]=a[l]; //当左端点等于右端点即建立叶子结点时,直接给数组信息赋值
7 else{
8 int m=l+((r-l)>>1); // m 为中间点,左儿子结点为 [l,m] ,右儿子结点为 [m+1,r];
9 build(o<<1,l,m); //构建左儿子结点
10 build((o<<1)|1,m+1,r); //构建右儿子结点
11 segtree[o]=segtree[o<<1]+segtree[(o<<1)|1]; //递归返回时用儿子结点更新父节点,此处可进行更新最大值、最小值、区间和等操作
12 }
13 }
14
15 { //在 main 函数中的语句
16 build(1,1,n);
17 }
然后是比较简单的单点修改以及区间查询操作:
单点修改:
1 void update(int o,int l,int r,int ind,int ans){ //o、l、r为当前更新到的结点、左右端点,ind为需要修改的叶子结点左端点,ans为需要修改成的值;
2 if(l==r){ //若当前更新点的左右端点相等即到叶子结点时,直接更新信息并返回
3 segtree[o]=ans;
4 return;
5 }
6 int m=l+((r-l)>>1);
7 if(ind<=m){ //若需要更新的叶子结点在当前结点的左儿子结点的范围内,则递归更新左儿子结点,否则更新右儿子结点
8 update(o<<1,l,m,ind,ans);
9 }
10 else{
11 update((o<<1)|1,m+1,r,ind,ans);
12 }
13 segtree[o]=max(segtree[o<<1],segtree[(o<<1)|1]);//递归回之后用儿子结点更新父节点(此处是区间最大值)
14 }
15
16 { //在main函数中的语句
17 update(1,1,n,ind,ans);
18 }
对应单点修改的区间查询:
1 int query(int o,int l,int r,int ql,int qr){ //ql、qr为需要查询的区间左右端点
2 if(ql>r||qr<l) return -1; //若当前结点和需要查找的区间不相交,则返回一个对于区间查询无关的值(如求和时返回0,求最大值时返回-1等,当然,一般是不会出现区间不相交的情况)
3 if(ql<=l&&qr>=r) return segtree[o]; //若需查询的区间正好为当前结点的区间,则返回当前结点的信息
4 int m=l+((r-l)>>1);
5 int p1=query(o<<1,l,m,ql,qr),p2=query((o<<1)|1,m+1,r,ql,qr); //p1为查询左儿子结点得到的信息,p2为查询右儿子结点得到的信息
6 return max(p1,p2); //综合两个儿子结点的信息并返回
7 }
8
9 { //main函数中的语句
10 printf("%d\n",query(1,1,n,a,b));
11 }
然后是线段数的区间修改以及相应的查询:
区间修改用到了lazy的思想,即当一个区间需要更新时,只递归更新到那一层结点,并将其下层结点所需要更新的信息保存在数组中,然后返回,只有当下次遍历到那个结点(更新过程中或查询过程中),才将那个结点的修改信息传递下去,这样就避免了区间修改的每个值的修改
区间修改(包括区间加值和区间赋值)及相应查询:
区间加值:
1 void pushup(int o){ //pushup函数,该函数本身是将当前结点用左右子节点的信息更新,此处求区间和,用于update中将结点信息传递完返回后更新父节点 2 segtree[o]=segtree[o<<1]+segtree[o<<1|1]; 3 } 4 5 void pushdown(int o,int l,int r){ //pushdown函数,将o结点的信息传递到左右子节点上 6 if(add[o]){ //当父节点有更新信息时才向下传递信息 7 add[o<<1]+=add[o]; //左右儿子结点均加上父节点的更新值 8 add[o<<1|1]+=add[o]; 9 int m=l+((r-l)>>1); 10 segtree[o<<1]+=add[o]*(m-l+1); //左右儿子结点均按照需要加的值总和更新结点信息 11 segtree[o<<1|1]+=add[o]*(r-m); 12 add[o]=0; //信息传递完之后就可以将父节点的更新信息删除 13 } 14 } 15 16 void update(int o,int l,int r,int ql,int qr,int addv){ //ql、qr为需要更新的区间左右端点,addv为需要增加的值 17 if(l==ql&&r==qr){ //与单点更新一样,当当前结点左右端点与需要更新的区间相同时 18 add[o]+=addv; //更新该结点的所需更新信息 19 segtree[o]+=addv*(r-l+1); //更新该结点信息 20 return; //根据lazy思想,由于不需要遍历到下层结点,因此不需要继续向下更新,直接返回 21 } 22 if(l==r)return; //若当前结点为叶子结点,为避免接下来pushup和pushdown时叶子结点没有子节点而出错所以遇到叶子结点时就直接返回(但其实应该不会遇到更新到叶子结点还不是需更新区间的情况,这样写应该只是保险) 23 pushdown(o,l,r); //将当前结点的所需更新信息传递到下一层(其左右儿子结点) 24 int m=l+((r-l)>>1); 25 if(qr<=m){ //当需更新区间在当前结点的左儿子结点内,则更新左儿子结点 26 update(o<<1,l,m,ql,qr,addv); 27 } 28 else if(ql>=m+1){ //当需更新区间在当前结点的右儿子结点内,则更新右儿子结点 29 update(o<<1|1,m+1,r,ql,qr,addv); 30 } 31 else{ //若不是上面两种情况,则表明需更新的区间被分割在左右儿子结点内,那么更新两个儿子结点 32 update(o<<1,l,m,ql,m,addv); 33 update(o<<1|1,m+1,r,m+1,qr,addv); 34 } 35 pushup(o); //递归回上层时一步一步更新回父节点 36 } 37 38 ll query(int o,int l,int r,int ql,int qr){ //ql、qr为需要查询的区间 39 if(l==ql&&r==qr) return segtree[o]; //若当前结点覆盖区间即为需要查询的区间,则直接返回当前结点的信息 40 pushdown(o,l,r); //将当前结点的更新信息传递给其左右子节点 41 int m=l+((r-l)>>1); 42 ll ans=0; //所需查询的结果 43 if(qr<=m){ //若所需查询的区间在当前结点的左子节点中,则结果等于查询其左子节点的结果 44 ans+=query(o<<1,l,m,ql,qr); 45 } 46 else if(ql>=m+1){ //若所需查询的区间在当前结点的右子节点中,则结果等于查询其右子节点的结果
47 ans+=query(o<<1|1,m+1,r,ql,qr);
48 }
49 else{ //若不是上面两种情况,则所需查询的区间被分割在左右子节点中,则结果等于查询其左右子节点的和
50 ans+=query(o<<1,l,m,ql,m);
51 ans+=query(o<<1|1,m+1,r,m+1,qr);
52 }
53 return ans;
54 }
区间改值(其实只有pushdow函数和update中修改部分与区间加值不同):
1 void pushup(int o){
2 segtree[o]=segtree[o<<1]+segtree[o<<1|1];
3 }
4
5 void pushdown(int o,int l,int r){ //pushdown和区间加值不同,改值时修改结点信息只需要对修改后的信息求和即可,不用加上原信息
6 if(change[o]){
7 int c=change[o];
8 change[o<<1]=c;
9 change[o<<1|1]=c;
10 int m=l+((r-l)>>1);
11 segtree[o<<1]=(m-l+1)*c;
12 segtree[o<<1|1]=(r-m)*c;
13 change[o]=0;
14 }
15 }
16
17 void update(int o,int l,int r,int ql,int qr,int c){
18 if(ql==l&&qr==r){ //同样更新结点信息和区间加值不同
19 change[o]=c;
20 segtree[o]=(r-l+1)*c;
21 return;
22 }
23 if(l==r)return;
24 pushdown(o,l,r);
25 int m=l+((r-l)>>1);
26 if(qr<=m){
27 update(o<<1,l,m,ql,qr,c);
28 }
29 else if(ql>=m+1){
30 update(o<<1|1,m+1,r,ql,qr,c);
31 }
32 else{
33 update(o<<1,l,m,ql,m,c);
34 update(o<<1|1,m+1,r,m+1,qr,c);
35 }
36 pushup(o);
37 }
38
39 int query(int o,int l,int r,int ql,int qr){
40 if(l==ql&&r==qr) return segtree[o];
41 pushdown(o,l,r);
42 int m=l+((r-l)>>1);
43 int ans=0;
44 if(qr<=m){
45 ans+=query(o<<1,l,m,ql,qr);
46 }
47 else if(ql>=m+1){
48 ans+=query(o<<1|1,m+1,r,ql,qr);
49 }
50 else{
51 ans+=query(o<<1,l,m,ql,m);
52 ans+=query(o<<1|1,m+1,r,m+1,qr);
53 }
54 return ans;
55 }
标签:
原文地址:http://www.cnblogs.com/cenariusxz/p/4336043.html