基础线段树总结

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

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

1、单点增减,区间求和

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

View Code
#include<algorithm>
#include<cstring>
#include<cstdio>
#define MAXN 500000
using namespace std;
struct SegTree
{
    int left,right;
    int anssum;
}tree[MAXN<<2];
void build(int root,int a,int b)
{
    tree[root].left=a;
    tree[root].right=b;
    tree[root].anssum=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 i,int e)//单点增减
{
    int L,M,R;
    L=tree[root].left;
    R=tree[root].right;
    tree[root].anssum+=e;
    if(L==R) return ;
    M=(L+R)>>1;
    if(i<=M)
        update(root<<1,i,e);
    else
        update(root<<1|1,i,e);
}
int query(int root,int a,int b)//区间求和
{
    int L,M,R;
    L=tree[root].left;
    R=tree[root].right;
    M=(L+R)>>1;
    if(a==L&&b==R)
        return tree[root].anssum;
    if(b<=M) return query(root<<1,a,b);
    else if(a>M) return query(root<<1|1,a,b);
    else return query(root<<1,a,M)+query(root<<1|1,M+1,b);
}
int main()
{
    int test,n,i,a,b,k=1;
    char s[5];
    scanf("%d",&test);
    while(test--)
    {
        scanf("%d",&n);
        build(1,1,n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a);
            update(1,i,a);
        }
        printf("Case %d:\n",k++);
        while(scanf("%s",s)&&strcmp(s,"End")!=0)
        {
            scanf("%d %d",&a,&b);
            if(s[0]=='Q') printf("%d\n",query(1,a,b));
            else if(s[0]=='A') update(1,a,b);
            else update(1,a,-b);
        }
    }
    return 0;
}

 

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

View Code
#include<iostream>
#include<cstdio>
#define MAXN 200000
using namespace std;
struct segtree
{
    int left,right;
    int ansmax;
}tree[MAXN<<2];
void build(int root,int a,int b)
{
    tree[root].left=a;
    tree[root].right=b;
    tree[root].ansmax=0;
    if(a<b)
    {
        int M=(tree[root].left+tree[root].right)>>1;
        build(root<<1,a,M);
        build(root<<1|1,M+1,b);
    }
}
void update(int root,int i,int e)
{
    tree[root].ansmax=max(tree[root].ansmax,e);
    if(tree[root].left==tree[root].right) return ;
    int M=(tree[root].left+tree[root].right)>>1;
    if(i<=M) update(root<<1,i,e);
    else update(root<<1|1,i,e);
}
int query(int root,int a,int b)
{
    if(tree[root].left==a&&tree[root].right==b)
    {
        return tree[root].ansmax;
    }
    int M=(tree[root].left+tree[root].right)>>1;
    if(b<=M) return query(root<<1,a,b);
    else if(a>M) return query(root<<1|1,a,b);
    else  return max(query(root<<1,a,M),query(root<<1|1,M+1,b));
}
int main()
{
    char s;
    int n,m,a,b,i;
    while(scanf("%d%d",&n,&m)==2)
    {
        build(1,1,n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a);
            update(1,i,a);
        }
        for(i=1;i<=m;i++)
        {
            scanf("%s%d%d",&s,&a,&b);
            if(s=='U') update(1,a,b);
            else printf("%d\n",query(1,a,b));
        }
    }
    return 0;
}

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

View Code
void update(int root,int i,int e)
{
    if(tree[root].left==tree[root].right)
    {
        tree[root].ansmax=max(tree[root].ansmax,e);
        return ;
    }
    int M=(tree[root].left+tree[root].right)>>1;
    if(i<=M) update(root<<1,i,e);
    else update(root<<1|1,i,e);
    tree[root].ansmax=max(tree[root<<1].ansmax,tree[root<<1|1].ansmax);
}

 

基础线段树练习:

练习一:http://acm.hdu.edu.cn/showproblem.php?pid=4339

练习二:http://210.32.0.220/onlinejudge/showProblem.do?problemCode=3635

 

你可能感兴趣的:(基础线段树总结)