【线段树入门题目集】

1.hdu1166

单点修改、区间和查询

注意:用位运算符的话要加最新标准的#include头文件,否则编译错误,数组开4*n大小(还是不够熟练)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define maxn 4*50005//开四倍!!
typedef long long ll;
using namespace std;
ll a[maxn],sum[maxn];
void update(ll i)
{
    sum[i]=sum[i<<1]+sum[i<<1|1];
}
void build(ll l,ll r,ll i)
{
    if(l==r)
    {
        sum[i]=a[l];
        return ;
    }
    ll mid=(l+r)>>1;
    build(l,mid,i<<1);
    build(mid+1,r,i<<1|1);
    update(i);
}
ll query(ll l,ll r,ll x,ll y,ll i)
{
    if(x<=l && r<=y)
        return sum[i];
    ll mid=(l+r)>>1,ans=0;
    if(x<=mid) ans+=query(l,mid,x,y,i<<1);
    if(y>=mid+1) ans+=query(mid+1,r,x,y,i<<1|1);
    return ans;
}
void change(ll pos,ll v,ll l,ll r,ll i)
{
    if(l==r)
    {
        sum[i]=sum[i]+v;
        return ;
    }
    ll mid=(l+r)>>1;
    if(pos<=mid) change(pos,v,l,mid,i<<1);
    else change(pos,v,mid+1,r,i<<1|1);
    update(i);
}
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    ll n,t,num=0,pos,v,x,y;
    string s;
    scanf("%lld",&t);
    while(t--)
    {
        memset(sum,0,sizeof(sum));
        printf("Case %lld:\n",++num);
        scanf("%lld",&n);
        for(ll i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        build(1,n,1);
        while(cin>>s && s!="End")
        {
            if(s=="Query")
            {
                scanf("%lld %lld",&x,&y);
                printf("%lld\n",query(1,n,x,y,1));
            }
            if(s=="Add"||s=="Sub")
            {
                scanf("%lld %lld",&pos,&v);
                if(s=="Add")
                 change(pos,v,1,n,1);
                else
                    change(pos,-v,1,n,1);
            }
        }
    }
    return 0;
}

2.POJ3468

区间修改,区间和查询(要在蓝书代码的基础上做一点修改,改了半天5555)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define maxn 4*111111//开四倍
typedef long long ll;
using namespace std;
ll a[maxn]={0},sum[maxn]={0},add[maxn]={0},sumv[maxn]={0};
void update(ll i,ll l,ll r)
{
    if(r>l)
        sum[i]=sumv[i<<1]+sumv[i<<1|1];//上一次操作后当前区间的值
    sumv[i]=sum[i]+add[i]*(r-l+1);//注意这个变化是在sum[i]的基础上,因为add[i]是累加的!
}
void build(ll l,ll r,ll i)
{
    if(l==r)
    {
        sum[i]=a[l];
        return ;
    }
    ll mid=(l+r)>>1;
    build(l,mid,i<<1);
    build(mid+1,r,i<<1|1);
    sum[i]=sum[i<<1]+sum[i<<1|1];
}
void change(ll v,ll i,ll l,ll r,ll x,ll y)//修改区间(x,y)
{
    if(x<=l && r<=y)//递归边界
    {
        add[i]+=v;
    }
    else
    {
        ll mid=(l+r)>>1;
        if(x<=mid) change(v,i<<1,l,mid,x,y);
        if(y>=mid+1) change(v,i<<1|1,mid+1,r,x,y);
    }
    update(i,l,r);
}
ll query(ll i,ll l,ll r,ll x,ll y,ll ad)
{
    if(x<=l && r<=y)
    {
        return sumv[i]+ad*(r-l+1);
    }
    ll mid=(l+r)>>1,ans=0;
    if(x<=mid) ans+=query(i<<1,l,mid,x,y,ad+add[i]);
    if(y>=mid+1) ans+=query(i<<1|1,mid+1,r,x,y,ad+add[i]);
    return ans;
}
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    ll n,q,v,x,y;
    char ch;
    scanf("%lld %lld",&n,&q);
    for(ll i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    build(1,n,1);
    memcpy(sumv,sum,sizeof(sum));
    while(q--)
    {
        cin>>ch;
        if(ch=='Q')
        {
            scanf("%lld %lld",&x,&y);
            printf("%lld\n",query(1,1,n,x,y,0));
        }
        else
        {
            scanf("%lld %lld %lld",&x,&y,&v);
            change(v,1,1,n,x,y);
        }
    }
    return 0;
}

这个才是真正的模版:注意scanf ch的时候要用getchar()

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define maxn 400005
typedef long long ll;
using namespace std;
ll add[maxn]={0},sum[maxn]={0},a[maxn]={0};
void pushup(ll i)
{
    sum[i]=sum[i<<1]+sum[i<<1|1];
}
void pushdown(ll i,ll l,ll r)//由父节点更新子结点的信息,并将父结点的懒人标记值置为0
{
    ll mid=(l+r)>>1;
    sum[i<<1]+=add[i]*(mid-l+1);
    sum[i<<1|1]+=add[i]*(r-mid);
    add[i<<1]+=add[i];
    add[i<<1|1]+=add[i];
    add[i]=0;
}
void build(ll i,ll l,ll r)
{
    if(l==r)
        sum[i]=a[l];
    else
    {
        ll mid=(l+r)>>1;
        build(i<<1,l,mid);
        build(i<<1|1,mid+1,r);
        pushup(i);
    }
}
void update(ll i,ll l,ll r,ll x,ll y,ll v)//把(x,y)范围内的数都增加v
{
    if(x<=l && r<=y)
    {
        add[i]+=v;
        sum[i]+=v*(r-l+1);
    }
    else
    {
        if(add[i]) pushdown(i,l,r);
        ll mid=(l+r)>>1;
        if(x<=mid) update(i<<1,l,mid,x,y,v);
        if(y>mid) update(i<<1|1,mid+1,r,x,y,v);
        pushup(i);
    }
}
ll query(ll i,ll l,ll r,ll x,ll y)//(x,y)和
{
    if(x<=l && r<=y)
        return sum[i];
    ll mid=(l+r)>>1,ans=0;
    if(add[i]) pushdown(i,l,r);
    if(x<=mid) ans+=query(i<<1,l,mid,x,y);
    if(y>mid) ans+=query(i<<1|1,mid+1,r,x,y);
    return ans;
}
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    ll n,q,x,y,v;
    char ch;
    scanf("%lld %lld",&n,&q);
    for(ll i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    build(1,1,n);
    while(q--)
    {
        cin>>ch;
        //getchar();
        if(ch=='Q')
        {
            scanf("%lld %lld",&x,&y);
            printf("%lld\n",query(1,1,n,x,y));
        }
        else
        {
            scanf("%lld %lld %lld",&x,&y,&v);
            //cout<

3.hdu1698

区间赋值,区间求和

只需要在第二题的代码中稍微修改一下就可以了,因为是区间赋值,所以add和sum不需要累加,直接用=就可以啦

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define maxn 400005
typedef long long ll;
using namespace std;
ll add[maxn]={0},sum[maxn]={0},a[maxn]={0};
void pushup(ll i)
{
    sum[i]=sum[i<<1]+sum[i<<1|1];
}
void pushdown(ll i,ll l,ll r)//由父节点更新子结点的信息,并将父结点的懒人标记值置为0
{
    ll mid=(l+r)>>1;
    sum[i<<1] = add[i]*(mid-l+1);
    sum[i<<1|1] = add[i]*(r-mid);
    add[i<<1] = add[i];
    add[i<<1|1] = add[i];
    add[i]=0;
}
void build(ll i,ll l,ll r)
{
    if(l==r)
        sum[i]=1;
    else
    {
        ll mid=(l+r)>>1;
        build(i<<1,l,mid);
        build(i<<1|1,mid+1,r);
        pushup(i);
    }
}
void update(ll i,ll l,ll r,ll x,ll y,ll v)//把(x,y)范围内的数都增加v
{
    if(x<=l && r<=y)
    {
        add[i] = v;
        sum[i] = v*(r-l+1);
    }
    else
    {
        if(add[i]) pushdown(i,l,r);
        ll mid=(l+r)>>1;
        if(x<=mid) update(i<<1,l,mid,x,y,v);
        if(y>mid) update(i<<1|1,mid+1,r,x,y,v);
        pushup(i);
    }
}
ll query(ll i,ll l,ll r,ll x,ll y)//(x,y)和
{
    if(x<=l && r<=y)
        return sum[i];
    ll mid=(l+r)>>1,ans=0;
    if(add[i]) pushdown(i,l,r);
    if(x<=mid) ans+=query(i<<1,l,mid,x,y);
    if(y>mid) ans+=query(i<<1|1,mid+1,r,x,y);
    return ans;
}
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    ll t,n,q,x,y,v,num=0;
    scanf("%lld",&t);
    while(t--)
    {
        memset(add,0,sizeof(add));
        memset(sum,0,sizeof(sum));
        scanf("%lld",&n);
        build(1,1,n);
        scanf("%lld",&q);
        while(q--)
        {
            scanf("%lld %lld %lld",&x,&y,&v);
            update(1,1,n,x,y,v);
        }
        printf("Case %lld: The total value of the hook is %lld.\n",++num,sum[1]);
    }
    return 0;
}

 

你可能感兴趣的:(线段树,线段树)