POJ--3468(线段树,区间修改,模板)

A Simple Problem with Integers

Time Limit: 5000MS   Memory Limit: 131072KB   64bit IO Format: %I64d & %I64u

Submit Status

Description

You have N integers, A1A2, ... , 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.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.

The second line contains N numbers, the initial values of A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.

Each of the next Q lines represents an operation.

"C abc" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.

"Q ab" means querying the sum of AaAa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

抄的大神的模板,注意懒惰标记的下传

代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
#include<set>
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxd=100000+5;
const int maxn=10000+5;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
typedef long long ll;
typedef pair<int,int> pii;
//---------------------------
int q,n;
ll add[maxd<<2],sum[maxd<<2];

void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}

void pushdown(int rt,int m)
{
    if(add[rt])
    {
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        sum[rt<<1]+=(add[rt] *(m-(m>>1)));
        sum[rt<<1|1]+=add[rt]*(m>>1);
        add[rt]=0;
    }
}

void build(int l,int r,int rt)
{
    add[rt]=0;
    if(l==r)
    {
        scanf("%lld",&sum[rt]);
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}

void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l && r<=R)
    {
        add[rt]+=c;
        sum[rt]+=(ll) c*(r-l+1);
        return;
    }
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m) update(L,R,c,lson);
    if(m<R) update(L,R,c,rson);
    pushup(rt);
}

ll query(int L,int R,int l,int r,int rt)
{
    if(L<=l && r<=R)
    {
        return sum[rt];
    }
    pushdown(rt,r-l+1);
    int m=(l+r)>>1;
    ll ret=0;
    if(L<=m) ret+=query(L,R,lson);
    if(m<R) ret+=query(L,R,rson);
    return ret;
}

int main()
{
    int kase;
    freopen("1.txt","r",stdin);
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        build(1,n,1);
        while(q--)
        {
            char op[5];
            int a,b,c;
            scanf("%s",op);
            if(op[0]=='C')
            {
                scanf("%d%d%d",&a,&b,&c);
                update(a,b,c,1,n,1);
            }
            else
            {
                scanf("%d%d",&a,&b);
                printf("%lld\n",query(a,b,1,n,1));
            }
        }
    }
    return 0;
}

时间: 2024-12-25 19:50:34

POJ--3468(线段树,区间修改,模板)的相关文章

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

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

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;

线段树区间修改模板

本来打算把大白书第三章一口气攻下来的,但是这个线段树也是卡了好久. 不敢过题太快,怕自己走马观花到头来结果什么都不会. 可也不能再拖了,在做题中也许有更多的体会. 模板一: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 表示

POJ 3468 线段树区间求和

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

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

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

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 59798   Accepted: 18237 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 2777 Count Color(线段树区间修改)

题目链接:http://poj.org/problem?id=2777 题目意思:就是问你在询问的区间里有几种不同的颜色 思路:这题和一般的区间修改差不多,但是唯一不同的就是我们要怎么计算有种颜色,所以这时候我们就需要把延时标记赋予不同的意义,当某段区间有多种颜色时就赋值为-1,当为一种颜色时就把它赋值为这个颜色的号数.这儿我们要怎么统计询问区间不同的颜色数叻,为了不重复计算同一种颜色,那么我们就需要用一个数组来标记计算过的颜色,当我们下次遇到时就不需要再次计算了.... 代码核心处就在计数那儿

【模板】线段树区间修改

区间修改: 区间修改过程类似于区间询问,例如将[ul, ur]内的所有元素都加上v,则进行如下操作: 当当前区间被区间[ul, ur]所包含时, 当前的节点值加上区间长度(r - l  + 1)乘以v 对当前节点的lazy-tag加上v,修改结束 否则,将当前节点的lazy-tag下传,分别修改左孩子和右孩子(一定条件下),然后更新此节点的值 lazy-tag下传: 如果当前节点没有lazy-tag,直接return 否则:1. 将左孩子右孩子分别加上lazy-tag * 区间长度的值  2.

POJ - 2528 Mayor&#39;s posters (离散化+线段树区间修改)

https://cn.vjudge.net/problem/POJ-2528 题意 给定一些海报,可能相互重叠,告诉你每个海报的宽度(高度都一样的)和先后叠放顺序,问没有被完全盖住的有多少张? 分析 海报最多10000张,但是墙有10000000块瓷砖长,海报不会落在瓷砖中间. 如果直接建树,就算不TLE,也会MLE.即单位区间长度太多. 其实10000张海报,有20000个点,最多有19999个区间.对各个区间编号,就是离散化.然后建树. 可以直接进行区间修改,最后再统计. 这里采用比较巧妙的