POJ-3468(线段树+区间更新+区间查询)

A Simple Problem With Integers

POJ-3468

  • 这题是区间更新的模板题,也只是区间更新和区间查询和的简单使用。
  • 代码中需要注意的点我都已经标注出来了,容易搞混的就是update函数里面还需要计算sum数组。因为这里查询的时候是直接用sum查询结点。
//区间更新,区间查询
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=100005;
long long num[maxn];
long long sum[maxn<<2];
long long lazy[maxn<<2];
int n,m;
void pushup(int id,int l,int r){
    int lc=id<<1;
    int rc=id<<1|1;
    sum[id]=sum[lc]+sum[rc];
}
void pushdown(int id,int l,int r){
    int lc=id<<1;
    int rc=id<<1|1;
    int mid=(l+r)>>1;
    lazy[lc]+=lazy[id];
    lazy[rc]+=lazy[id];
    sum[lc]+=lazy[id]*(mid-l+1);
    sum[rc]+=lazy[id]*(r-mid-1+1);
    lazy[id]=0;
}
void build(int id,int l,int r){
    if(l==r){
        sum[id]=num[l];
        return;
    }
    int lc=id<<1;
    int rc=id<<1|1;
    int mid=(l+r)>>1;
    build(lc,l,mid);
    build(rc,mid+1,r);
    pushup(id,l,r);//向上维护
}
void update(int id,int l,int r,int p,int q,int v){
    if(p<=l&&q>=r){//完全包含区间
        lazy[id]+=v;
        sum[id]+=v*(r-l+1);//-----------------------这一步容易忘记
        return;
    }
    pushdown(id,l,r);//---------------------这一步也容易忘记
    int mid=(l+r)>>1;
    int lc=id<<1,rc=id<<1|1;
    if(p<=mid){
        update(lc,l,mid,p,q,v);
    }
    if(q>mid){
        update(rc,mid+1,r,p,q,v);
    }
    pushup(id,l,r);
}
long long query(int id,int l,int r,int p,int q){
    long long sums=0;
    if(p<=l&&q>=r){
        //return sums=sum[id]+lazy[id]*(r-l+1);
        return sums=sum[id];
    }
    pushdown(id,l,r);
    int mid=(l+r)>>1;
    if(p<=mid){
        sums+=query(id<<1,l,mid,p,q);
    }
    if(q>mid){
        sums+=query(id<<1|1,mid+1,r,p,q);
    }
    //pushup(id,l,r);//----------因为这里是查询函数,所以可以省略。这里在pushdown函数里面做过类似的。
    return sums;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>n>>m){
        memset(lazy,0,sizeof(lazy));
        for(int i=1;i<=n;i++){
            cin>>num[i];
        }
        build(1,1,n);
        for(int i=0;i<m;i++){
            char c;
            cin>>c;
            if(c=='C'){//add,更新
                int a,b,c;
                cin>>a>>b>>c;
                update(1,1,n,a,b,c);
            }else{//查询
                int a,b;
                cin>>a>>b;
                cout<<query(1,1,n,a,b)<<endl;
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/GarrettWale/p/11447341.html

时间: 2024-10-27 20:00:51

POJ-3468(线段树+区间更新+区间查询)的相关文章

hdu 1698+poj 3468 (线段树 区间更新)

http://acm.hdu.edu.cn/showproblem.php?pid=1698 这个题意翻译起来有点猥琐啊,还是和谐一点吧 和涂颜色差不多,区间初始都为1,然后操作都是将x到y改为z,注意 是改为z,不是加或减,最后输出区间总值 也是线段树加lazy操作 1 #include<cstdio> 2 using namespace std; 3 struct point { 4 int l,r; 5 int val,sum; 6 }; 7 point tree[400007]; 8

A Simple Problem with Integers POJ - 3468 线段树区间修改+区间查询

//add,懒标记,给以当前节点为根的子树中的每一个点加上add(不包含根节点) // #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; const int N = 100010; int n, m; int w[N]; struct Node { int l, r;

POJ 3468 线段树区间求和

线段树区间求和树节点不能只存和,只存和,会导致每次加数的时候都要更新到叶子节点,速度太慢(O(nlogn)).所以我们要存两个量,一个是原来的和nSum,一个是累加的增量Inc. 在增加时,如果要加的区间正好覆盖一个节点,则增加其节点的Inc值,不再往下走,否则要更新nSum(加上本次增量),再将增量往下传,这样更新的复杂度就是O(log(n)). 在查询时,如果待查区间不是正好覆盖一个节点,就将节点的Inc往下带,然后将Inc清0,接下来再往下查询. Inc往下带的过程也是区间分解的过程,复杂

POJ 3468 A Simple Problem with Integers 线段树 区间更新 区间查询

题目链接: http://poj.org/problem?id=3468 题目描述: 一组数列, 可进行一段区间加上某一个数, 和区间查询 解题思路: 线段树, 之前的那道题是求总区间直接输出sum[1] 就可以了, 这次有了区间查询, 同理, 查询的时候Pushdown 代码: #include <iostream> #include <cstdio> #include <string> #include <vector> #include <map

C - A Simple Problem with Integers POJ - 3468 线段树模版(区间查询区间修改)

参考qsc大佬的视频 太强惹 先膜一下 视频在b站 直接搜线段树即可 1 #include<cstdio> 2 using namespace std; 3 const int maxn=1e5+6; 4 int n,a[maxn]; 5 struct Node{ 6 int l,r; 7 long long sum,lazy; 8 void update(long long x){//用于更新区间和 和懒标记 9 sum+=1ll*(r-l+1)*x; 10 lazy+=x; 11 } 12

POJ 3468 (线段树 区间增减) A Simple Problem with Integers

这题WA了好久,一直以为是lld和I64d的问题,后来发现是自己的pushdown函数写错了,说到底还是因为自己对线段树理解得不好. 因为是懒惰标记,所以只有在区间分开的时候才会将标记往下传递.更新和查询都要pushdown. 1 #include <cstdio> 2 3 typedef long long LL; 4 5 const int maxn = 100000 + 10; 6 7 int n, m, qL, qR, v; 8 LL sum[maxn << 2], add

POJ - 3468 线段树区间修改,区间求和

由于是区间求和,因此我们在更新某个节点的时候,需要往上更新节点信息,也就有了tree[root].val=tree[L(root)].val+tree[R(root)].val; 但是我们为了把懒标记打上,当节点表示的区间是完全被询问区间包含,那么这个区间的信息都是有用的,因此我们其实只需要把这个节点更新,并打上懒标记即可.如果以后update 或者 query 需要跑到下面,直接往下pushdown即可. pushdown的时候,由于当前层的信息已经更新,我们需要把信息往下推,并把子节点的信息

CDOJ 1057 秋实大哥与花 线段树 区间更新+区间查询

链接: I - 秋实大哥与花 Time Limit:1000MS     Memory Limit:65535KB     64bit IO Format:%lld & %llu Submit Status Practice UESTC 1057 Appoint description:  System Crawler  (2016-04-19) Description 秋实大哥是一个儒雅之人,昼听笙歌夜醉眠,若非月下即花前. 所以秋实大哥精心照料了很多花朵.现在所有的花朵排成了一行,每朵花有一

POJ 3225 (线段树 区间更新) Help with Intervals

这道题搞了好久,其实坑点挺多.. 网上找了许多题解,发现思路其实都差不多,所以就不在重复了. 推荐一篇比较好的题解,请戳这. 另外,如果因为可能要更新多次,但最终查询只需要一次,所以没有写pushup函数,仅有一个pushdown. 1 #include <cstdio> 2 3 const int maxn = 131072; 4 //const int maxn = 10; 5 int qL, qR, op; 6 int setv[maxn << 2], xorv[maxn &