线段树

 1 //线段树的节点
 2 //节点包括两部分信息,基本域,和信息域
 3 //基本域:左右边界ld,rd.  左右孩子:lc,rc
 4 //信息域:key值,如RMQ问题中,信息域中存储的是区间最大值
 5 struct Node{
 6     int ld,rd;
 7     Node *lc,*rc;
 8     int key;
 9 };
10  
11 //空树的建立,内含key值的初始化;
12 //一般在主函数中首先调用 Node* root= buildtree(1,n);建立一棵新树
13 Node *buildtree(int a,int b){
14     Node * p=new Node;//给P申请一块内存
15     p->ld=a;
16     p->rd=b;
17     //{初始化 p->key }
18     if(a==b)return p;//叶子节点
19     p->lc=buildtree(a,(a+b)/2);
20     p->rc=buildtree((a+b)/2+1,b);
21     return p;
22 }
23  
24 void insert(Node *T,int a,int b,int key){
25     if(a<=T->ld&&b>=T->rd){
26         //{根据key处理T->key; 然后 return ;}
27     }
28     if(a<=(T->ld+T->rd)/2)
29         insert(T->lc,a,b,key);
30     if(b>(T->ld+T->rd)/2)
31         insert(T->rc,a,b,key);
32     //{根据T->lc和T->rc的信息处理T->key}  (此处类似于归并排序中最后的合并操作)
33 }
34  
35 int search(Node *T,int a,int b){
36     int res;
37     if(a<=T->ld&&b>=T->rd)
38         // {根据T->key处理res;return res;}
39     if(a<=(T->ld+T->rd)/2)
40         //{根据search(T->lc,a,b)处理res}
41     if(b>(T->ld+T->rd)/2)
42         //根据search(T->rc,a,b)处理res}
43     return res;
44 }

模板:

基础线段树是一些基本操作之间的组合:

基本操作:单点更新、单点查询、区间更新,区间求和、区间最值

1、单点增减,区间求和

http://acm.hdu.edu.cn/showproblem.php?pid=1166

 1 View Code 
 2 
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cstdio>
 6 #define MAXN 500000
 7 using namespace std;
 8 struct SegTree
 9 {
10     int left,right;
11     int anssum;
12 }tree[MAXN<<2];
13 void build(int root,int a,int b)
14 {
15     tree[root].left=a;
16     tree[root].right=b;
17     tree[root].anssum=0;
18     if(a<b)
19     {
20         int M=(a+b)>>1;
21         build(root<<1,a,M);
22         build(root<<1|1,M+1,b);
23     }
24 }
25 void update(int root,int i,int e)//单点增减
26 {
27     int L,M,R;
28     L=tree[root].left;
29     R=tree[root].right;
30     tree[root].anssum+=e;
31     if(L==R) return ;
32     M=(L+R)>>1;
33     if(i<=M)
34         update(root<<1,i,e);
35     else
36         update(root<<1|1,i,e);
37 }
38 int query(int root,int a,int b)//区间求和
39 {
40     int L,M,R;
41     L=tree[root].left;
42     R=tree[root].right;
43     M=(L+R)>>1;
44     if(a==L&&b==R)
45         return tree[root].anssum;
46     if(b<=M) return query(root<<1,a,b);
47     else if(a>M) return query(root<<1|1,a,b);
48     else return query(root<<1,a,M)+query(root<<1|1,M+1,b);
49 }
50 int main()
51 {
52     int test,n,i,a,b,k=1;
53     char s[5];
54     scanf("%d",&test);
55     while(test--)
56     {
57         scanf("%d",&n);
58         build(1,1,n);
59         for(i=1;i<=n;i++)
60         {
61             scanf("%d",&a);
62             update(1,i,a);
63         }
64         printf("Case %d:\n",k++);
65         while(scanf("%s",s)&&strcmp(s,"End")!=0)
66         {
67             scanf("%d %d",&a,&b);
68             if(s[0]=='Q') printf("%d\n",query(1,a,b));
69             else if(s[0]=='A') update(1,a,b);
70             else update(1,a,-b);
71         }
72     }
73     return 0;
74 }

 

2、区间更新、单点访问

http://acm.nyist.net/JudgeOnline/problem.php?pid=123

View Code 

#include<algorithm>
#include<cstring>
#include<cstdio>
#define MAXN 1000000
using namespace std;
struct SegTree
{
    int left,right;
    int acount;
} tree[MAXN<<2];
void build(int root,int a,int b)
{
    tree[root].left=a;
    tree[root].right=b;
    tree[root].acount=0;
    if(a<b)
    {
        int M=(a+b)>>1;
        build(root<<1,a,M);
        build(root<<1|1,M+1,b);
    }
}
void update(int root,int a,int b,int c)//区间更新
{
    if(a<=tree[root].left&&tree[root].right<=b)
    {
        tree[root].acount+=c;
        return ;
    }
    int M=(tree[root].left+tree[root].right)>>1;
    if(b<=M) update(root<<1,a,b,c);
    else if(a>M) update(root<<1|1,a,b,c);
    else
    {
        update(root<<1,a,M,c);
        update(root<<1|1,M+1,b,c);
    }
}
int query(int root,int a)//单点访问
{
    int cnt=tree[root].acount;
    int M=(tree[root].left+tree[root].right)>>1;
    if(tree[root].left==tree[root].right) return cnt;
    if(a<=M)  cnt+=query(root<<1,a);
    else cnt+=query(root<<1|1,a);
    return cnt;
}
int main()
{
    int n,m,a,b,c,i;
    char str[10];//这里被坑了str[5]
    scanf("%d%d",&m,&n);
    build(1,1,n);
    for(i=1; i<=m; i++)
    {
        scanf("%s",str);
        if(str[0]=='A')
        {
            scanf("%d%d%d",&a,&b,&c);
            update(1,a,b,c);
        }
        else
        {
            scanf("%d",&a);
            printf("%d\n",query(1,a));
        }
    }
    return 0;
}

3、单点替换、区间最值

http://acm.hdu.edu.cn/showproblem.php?pid=1754

 1 View Code 
 2 
 3 #include<iostream>
 4 #include<cstdio>
 5 #define MAXN 200000
 6 using namespace std;
 7 struct segtree
 8 {
 9     int left,right;
10     int ansmax;
11 }tree[MAXN<<2];
12 void build(int root,int a,int b)
13 {
14     tree[root].left=a;
15     tree[root].right=b;
16     tree[root].ansmax=0;
17     if(a<b)
18     {
19         int M=(tree[root].left+tree[root].right)>>1;
20         build(root<<1,a,M);
21         build(root<<1|1,M+1,b);
22     }
23 }
24 void update(int root,int i,int e)
25 {
26     tree[root].ansmax=max(tree[root].ansmax,e);
27     if(tree[root].left==tree[root].right) return ;
28     int M=(tree[root].left+tree[root].right)>>1;
29     if(i<=M) update(root<<1,i,e);
30     else update(root<<1|1,i,e);
31 }
32 int query(int root,int a,int b)
33 {
34     if(tree[root].left==a&&tree[root].right==b)
35     {
36         return tree[root].ansmax;
37     }
38     int M=(tree[root].left+tree[root].right)>>1;
39     if(b<=M) return query(root<<1,a,b);
40     else if(a>M) return query(root<<1|1,a,b);
41     else  return max(query(root<<1,a,M),query(root<<1|1,M+1,b));
42 }
43 int main()
44 {
45     char s;
46     int n,m,a,b,i;
47     while(scanf("%d%d",&n,&m)==2)
48     {
49         build(1,1,n);
50         for(i=1;i<=n;i++)
51         {
52             scanf("%d",&a);
53             update(1,i,a);
54         }
55         for(i=1;i<=m;i++)
56         {
57             scanf("%s%d%d",&s,&a,&b);
58             if(s=='U') update(1,a,b);
59             else printf("%d\n",query(1,a,b));
60         }
61     }
62     return 0;
63 }

注:单点增减、区间最值(update使用自底向上的方式有点慢)

 1 View Code 
 2 
 3 #include<iostream>
 4 #include<cstdio>
 5 #define MAXN 200000
 6 using namespace std;
 7 struct segtree
 8 {
 9     int left,right;
10     int ansmax;
11 }tree[MAXN<<2];
12 void build(int root,int a,int b)
13 {
14     tree[root].left=a;
15     tree[root].right=b;
16     tree[root].ansmax=0;
17     if(a<b)
18     {
19         int M=(tree[root].left+tree[root].right)>>1;
20         build(root<<1,a,M);
21         build(root<<1|1,M+1,b);
22     }
23 }
24 void update(int root,int i,int e)
25 {
26     tree[root].ansmax=max(tree[root].ansmax,e);
27     if(tree[root].left==tree[root].right) return ;
28     int M=(tree[root].left+tree[root].right)>>1;
29     if(i<=M) update(root<<1,i,e);
30     else update(root<<1|1,i,e);
31 }
32 int query(int root,int a,int b)
33 {
34     if(tree[root].left==a&&tree[root].right==b)
35     {
36         return tree[root].ansmax;
37     }
38     int M=(tree[root].left+tree[root].right)>>1;
39     if(b<=M) return query(root<<1,a,b);
40     else if(a>M) return query(root<<1|1,a,b);
41     else  return max(query(root<<1,a,M),query(root<<1|1,M+1,b));
42 }
43 int main()
44 {
45     char s;
46     int n,m,a,b,i;
47     while(scanf("%d%d",&n,&m)==2)
48     {
49         build(1,1,n);
50         for(i=1;i<=n;i++)
51         {
52             scanf("%d",&a);
53             update(1,i,a);
54         }
55         for(i=1;i<=m;i++)
56         {
57             scanf("%s%d%d",&s,&a,&b);
58             if(s=='U') update(1,a,b);
59             else printf("%d\n",query(1,a,b));
60         }
61     }
62     return 0;
63 }
原文地址:https://www.cnblogs.com/xiaofanke/p/3011203.html