線段樹區間修改與查詢


單點修改與查詢

 

//單點修改,區間詢問最小值
#include <iostream>
#include <cstdio>
#define maxn 101
#define INF 0x7fffffff
using namespace std;

int a[maxn],n,m;
int mi[maxn];

void build(int k,int l,int r)//k是當前節點編號,l,r為當前節點代表區間
{
    if(l==r)
    {
        mi[k]=a[l];
        return;
    }
    int mid=(l+r)/2;
    build(k*2,l,mid);//左子樹
    build(k*2+1,mid+1,r);//右子樹
    mi[k]=min(mi[2*k],mi[2*k+1]);//維護最小值
}//建立線段樹

int query(int k,int l,int r,int x,int y)//x,y為詢問區間,l,r為當前區間
{
    if(y<l||x>r)return INF;//詢問區間與當前區間完全無交集
    if(x<=l&&y>=r)
    {
        return mi[k];
    }//詢問區間完全包含當前區間
    int mid=(l+r)/2;

    return min(query(k*2,l,mid,x,y),query(k*2+1,mid+1,r,x,y));//否則分別處理左右子樹

}

void update(int k,int l,int r,int x,int v)//x為原序列位置,v為要修改的值
{
    if(r<x||l>x)return; //當前區間與原序列位置完全無交集
    if(l==r&&l==x)//當前節點為葉子結點
    {
        mi[k]=v;//修改葉子結點
        return;
    }
    int mid=(l+r)/2;
    update(k*2,l,mid,x,v);
    update(k*2+1,mid+1,r,x,v);
    mi[k]=min(mi[k*2],mi[k*2+1]);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int k,l,r;
        scanf("%d%d%d",&k,&l,&r);
        if(k==0)//更新
        {
            update(1,1,n,l,r);
        }
        if(k==1)
        {
            int ans=query(1,1,n,l,r);
            printf("%d\n",ans);
        }
    }

    return 0;
}

 

區間修改與查詢

注意要使用標記下傳來實現。

 

//線段樹-區間修改,查詢區間和
#include <iostream>
#include <cstdio>
#define ll long long
#define maxn 1000005
using namespace std;

ll sum[maxn];//序號為k的區間的區間和
ll a[maxn];
ll add[maxn];//lazy標記
int n,m;

void build(int k,int l,int r)
{
    if(l==r)
    {
        sum[k]=a[l];
        return;
    }
    int mid=(l+r)/2;
    build(2*k,l,mid);
    build(2*k+1,mid+1,r);
    sum[k]=sum[2*k]+sum[2*k+1];
}//建立線段樹,維護區間和

void Add(int k,int l,int r,ll v)//給定區間[l,r]所有數加上v(打標記)
{
    add[k]+=v;
    sum[k]+=(r-l+1)*v;//維護區間和
    return;
}

void pushdown(int k,int l,int r,int mid)//標記下傳
{
    if(add[k]==0)return;
    Add(k*2,l,mid,add[k]);//下傳到左子樹
    Add(k*2+1,mid+1,r,add[k]);//下傳到右子樹
    add[k]=0; //清零標記
}

void modify(int k,int l,int r,int x,int y,ll v)//給區間[x,y]所有的數加上v(真的加上)
{
    if(l>=x&&r<=y)
    {
        return Add(k,l,r,v);
    }
    int mid=(l+r)/2;
    pushdown(k,l,r,mid); //到達每一個結點都要下傳標記
    if(x<=mid)modify(2*k,l,mid,x,y,v);//修改左子樹
    if(y>mid)modify(2*k+1,mid+1,r,x,y,v);//修改右子樹
    sum[k]=sum[2*k]+sum[2*k+1];
}

ll query(int k,int l,int r,int x,int y)
{
    if(l>=x&&r<=y)
    {
        return sum[k];
    }
    int mid=(l+r)/2;
    ll res=0;
    pushdown(k,l,r,mid);
    if(x<=mid)
    {
        res+=query(k*2,l,mid,x,y);
    }
    if(y>mid)
    {
        res+=query(k*2+1,mid+1,r,x,y);
    }
    return res;
}//詢問區間[x,y]的區間和

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int op,l,r;
        scanf("%d%d%d",&op,&l,&r);
        if(op==1)
        {
            ll v;
            scanf("%lld",&v);
            modify(1,1,n,l,r,v);
        }
        if(op==2)
        {
            ll ans=query(1,1,n,l,r);
            printf("%lld\n",ans);
        }
    }

    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM