线段树区间修改与查询

单点修改与查询

//单点修改,区间询问最小值
#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;
}

原文地址:https://www.cnblogs.com/Bw-Orzzzzz/p/10829082.html

时间: 2024-08-29 19:34:39

线段树区间修改与查询的相关文章

Wikilo 1191线段树区间修改单点查询

这题也算比较容易的了. 如果哪个区间已经没有黑色的话,就不用update了,就是因为这个原因WA了2发,唉-- #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <queue> #include <string> #incl

POJ 3468 A Simple Problem with Integers(线段树区间修改及查询)

Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval. In

uva 1401 Fast Matrix Operations 快速矩阵操作 (线段树 区间修改和查询)

题意:给一个r行c列的全0矩阵,支持以下三种操作: 1 x1 y1 x2 y2 v 子矩阵(x1 y1 x2 y2)的所有元素增加v 2 x1 y1 x2 y2 v 子矩阵(x1 y1 x2 y2)的所有元素设为v 3 x1 y1 x2 y2   查询子矩阵(x1 y1 x2 y2)的元素和.最小值.最大值. 子矩阵(x1 y1 x2 y2)是指满足 x1 <= x <= x2, y1 <= y <= y2的所有元素(x,y). 矩阵不超过20行,矩阵总元素可多达10^6个. 思路

HDU 5861 Road(线段树 区间修改 单点查询)

Road Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1132    Accepted Submission(s): 309 Problem Description There are n villages along a high way, and divided the high way into n-1 segments. E

hdu1698 Just a Hook(线段树+区间修改+区间查询+模板)

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 54923    Accepted Submission(s): 25566 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of

P2023 [AHOI2009]维护序列 (线段树区间修改查询)

题目链接:https://www.luogu.org/problemnew/show/P2023 一道裸的线段树区间修改题,懒惰数组注意要先乘后加 #include<bits/stdc++.h> using namespace std; typedef long long LL; const int maxx = 400010; LL tree[maxx],lazy1[maxx],lazy2[maxx],a[maxx],mod; int n; void build(int l,int r,in

线段树区间修改模板

本来打算把大白书第三章一口气攻下来的,但是这个线段树也是卡了好久. 不敢过题太快,怕自己走马观花到头来结果什么都不会. 可也不能再拖了,在做题中也许有更多的体会. 模板一:1 L R v 表示区间[L, R]所有元素都加上v2 L R   表示查询区间[L, R]的sum, min, maxsumv[o]的定义为:如果只执行节点o及其子孙节点的中的add操作,节点o对应区间中所有数之和 1 //线段树区间修改 2 //1 L R v 表示区间[L, R]所有元素都加上v 3 //2 L R 表示

UVA11992 - Fast Matrix Operations ( 线段树 + 区间修改 + 好题 )

UVA11992 - Fast Matrix Operations ( 线段树 + 区间修改 + 好题 ) 这是大白书上的例题,一直放着没有去A掉,这是一道线段树区间修改的好题. 线段树中需要维护三个域 ,max, min, sum,也就是区间最大值,最小值,区间和 题目大意: r 行 c 列 的全0矩阵,支持三个操作 1 x1 y1 x2 y2 v 子矩阵(x1,y1,x2,y2)的所有元素增加v 2 x1 y1 x2 y2 v 子矩阵(x1,y1,x2,y2)的所有元素设为v 3 x1 y1

POJ 2777 Count Color (线段树区间更新加查询)

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d