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;
    //总和
    //如果只考虑当前节点及子节点上的标记,当前区间和是多少  ,没考虑所有祖先节点上的标记
    LL sum;
    //懒标记
    //给当前区间的所有儿子加上add
    LL add;
}tr[N * 4];
//用子节点的信息来计算父节点的信息
void pushup(int u)
{
    tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void pushdown(int u)
{
    Node &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
    //如果当前根节点有标记,往下传,还要清空
    if (root.add)
    {
        left.add += root.add;
        left.sum += (LL)(left.r - left.l + 1) * root.add;
        right.add += root.add;
        right.sum += (LL)(right.r - right.l + 1) * root.add;
        root.add = 0;
    }
}
void build(int u, int l, int r)
{
    if (l == r)
        tr[u] = {l, r, w[r], 0};
    else
    {
        tr[u] = {l, r};
        int mid = l + r >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}
void modify(int u, int l, int r, int d)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        //总和
        tr[u].sum += (LL)(tr[u].r - tr[u].l + 1) * d;
        //懒标记
        tr[u].add += d;
    }
    // 区间太大,一定要分裂
    else
    {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid)
            modify(u << 1, l, r, d);
        if (r > mid)
            modify(u << 1 | 1, l, r, d);
        //当前区间和发生变化,需要向上传
        pushup(u);
    }
}
LL query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
        return tr[u].sum;
    //查询子区间
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    LL sum = 0;
    if (l <= mid)
        sum = query(u << 1, l, r);
    if (r > mid)
        sum += query(u << 1 | 1, l, r);
    return sum;
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ )
        scanf("%d", &w[i]);
    build(1, 1, n);
    char op[2];
    int l, r, d;
    while (m -- )
    {
        scanf("%s%d%d", op, &l, &r);
        if (*op == ‘C‘)
        {
            scanf("%d", &d);
            modify(1, l, r, d);
        }
        else printf("%lld\n", query(1, l, r));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12293719.html

时间: 2024-07-29 07:36:27

A Simple Problem with Integers POJ - 3468 线段树区间修改+区间查询的相关文章

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

A Simple Problem with Integers POJ - 3468 (线段树)

思路:线段树,区间更新,区间查找 1 #include<iostream> 2 #include<vector> 3 #include<string> 4 #include<cmath> 5 #include<set> 6 #include<algorithm> 7 #include<cstdio> 8 #include<map> 9 #include<cstring> 10 #include<

A Simple Problem with Integers poj 3468 多树状数组解决区间修改问题。

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 69589   Accepted: 21437 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

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

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

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

C - A Simple Problem with Integers POJ 3468

C - A Simple Problem with Integers Time Limit:5000MS Memory Limit:131072KB 64bit IO Format:%I64d & %I64u Submit Status Practice POJ 3468 Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of ope

hdu 4267 A Simple Problem with Integers(树形结构-线段树)

A Simple Problem with Integers Time Limit: 5000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3708    Accepted Submission(s): 1139 Problem Description Let A1, A2, ... , AN be N elements. You need to deal with

POJ 3468 线段树区间求和

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

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