poj3468 线段树+lazy标记

A Simple Problem with Integers

Time Limit: 5000MS   Memory Limit: 131072K
Total Submissions: 92921   Accepted: 28910
Case Time Limit: 2000MS

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.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+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

Hint

The sums may exceed the range of 32-bit integers.

题目大意:

给你n个数,然后会进行q次操作,Q a b为查询区间[a,b]所有数的和sum,

C a b c ,为将区间[a,b]所有数整体加c。

思路分析:如果只是改变某一个数的值,我们直接用一个裸的线段树来维护就行,但是这个题是

区间的值整体发生变化,如果再进行和以前一样的操作,则update的复杂度变成了LlogL(L为

区间长度)很不高效,势必超时,因此我们可以采用lazy标记的方法,用空间换时间,开一个lazy

数组,每次不必访问到根节点,只需要到更新的区间所在的节点就可以,大大提高了程序效率,只需要

明确lazy标记什么时候往儿子传就可以,一个是要往子节点更新,另一个是即将要查询子节点,都要将

lazy标记向下传一层,传给自己的儿子,增值会爆int,需要用long long

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn=100000+100;
typedef long long ll;
ll tree[3*maxn];
ll lazy[3*maxn];
ll num[maxn];
void build (int p,int l,int r)
{
    if(l==r) {tree[p]=num[l];return;}
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build((p<<1)|1,mid+1,r);
    tree[p]=tree[p<<1]+tree[(p<<1)|1];
}
void pushdown(int p,int m)//把lazy标记下放到儿子节点
{
    if(lazy[p])
    {
        lazy[p<<1]+=lazy[p];
        lazy[(p<<1)|1]+=lazy[p];
        tree[p<<1]+=(m-(m>>1))*lazy[p];
        tree[(p<<1)|1]+=(m>>1)*lazy[p];
        lazy[p]=0;
    }
}
void update(int p,int l,int r,int x,int y,int v)
{
    if(x<=l&&y>=r)
    {
        lazy[p]+=v;
        tree[p]+=(ll)v*(r-l+1);//区间长度
        return;
    }
    pushdown(p,r-l+1);
    int mid=(l+r)>>1;
    if(y<=mid) update(p<<1,l,mid,x,y,v);
    else if(x>mid) update((p<<1)|1,mid+1,r,x,y,v);
    else {update(p<<1,l,mid,x,mid,v),update((p<<1)|1,mid+1,r,mid+1,y,v);}
    tree[p]=tree[p<<1]+tree[(p<<1)|1];
}
ll find(int p,int l,int r,int x,int y)
{
    if(x<=l&&y>=r){return tree[p];}
    pushdown(p,r-l+1);
    int mid=(l+r)>>1;
    ll ans=0;
    if(y<=mid) ans=find(p<<1,l,mid,x,y);
    else if(x>mid) ans=find((p<<1)|1,mid+1,r,x,y);
    else ans=find(p<<1,l,mid,x,mid)+find((p<<1)|1,mid+1,r,mid+1,y);
    return ans;
}
int main()
{
     int n,q;
     char s[5];
     int a,b,c;
    while(~scanf("%d%d",&n,&q))
    {
        memset(tree,0,sizeof(tree));
        memset(lazy,0,sizeof(lazy));
        for(int i=1;i<=n;i++)
            scanf("%lld",&num[i]);
        build(1,1,n);
        while(q--)
        {
            scanf("%s",s);
            if(s[0]==‘Q‘)
            {
                scanf("%d%d",&a,&b);
                printf("%lld\n",find(1,1,n,a,b));
            }
            else
            {
                scanf("%d%d%d",&a,&b,&c);
                update(1,1,n,a,b,c);
            }
        }
    }
}
时间: 2024-07-30 11:35:01

poj3468 线段树+lazy标记的相关文章

线段树lazy标记??Hdu4902

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 335    Accepted Submission(s): 159 Problem Description There is an old country and the king fell in love with a devil. The devil al

fzu 2171 线段树 lazy标记

http://acm.fzu.edu.cn/problem.php?pid=2171      Problem 2171 防守阵地 II Accept: 73    Submit: 256Time Limit: 3000 mSec    Memory Limit : 32768 KB Problem Description 部队中总共有N个士兵,每个士兵有各自的能力指数Xi,在一次演练中,指挥部确定了M个需要防守的地点,指挥部将选择M个士兵依次进入指定地点进行防守任务,获得的参考指数即为M个士兵

POJ 3468 线段树+lazy标记

lazy标记 Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I64u Submit Status 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

[hiho 22]线段树-lazy标记的下放

题目描述 之前提到过,线段树之所以更新查询快,是因为区间更新有lazy标记使得不需要每次都操作到叶子节点. 但是如果要操作一个节点时,其父节点上的lazy标记应当被释放,否则该节点无法得到最新的正确结果. 因而lazy标记下放的策略是在需要操作某个节点的子节点时,将该节点的lazy标记全部下放.见第69行. 同时应当注意,给某个节点增加lazy标记时,不要忘了修改该节点的相关统计值.因为更新完该节点后还要马上修改其父节点的统计值.见第80行. 代码如下: #include <stdio.h>

poj 4047 Garden 线段树lazy标记与成段更新

题意: 给长度为n的序列及k(0<k<=n<=200000),m个操作p,x,y.其中(1)p==0:将x位置处的数变为y;(2)p==1:将x,y位置处的数互换.(3)p==2查询x-y位置之间连续k个数的和的最大值. 分析: 求连续区间的和最大,可以把区间看成一个点,这样这n-k+1个区间的最大和可以看做n-k+1个点的最大值,当更新原序列中位置x的值就相当于更新区间中x-k+1到x区间的值,然后用线段树做成段更新.成段更新要用到lazy标记,我的理解是:当更新或query的时候如果

线段树(lazy标记)

1 # include<cstdio> 2 # include<iostream> 3 4 using namespace std; 5 6 # define MAX 100004 7 # define lid id<<1 8 # define rid id<<1|1 9 10 typedef long long LL; 11 int n; 12 13 struct Segtree 14 { 15 int l,r; 16 LL lazy,sum; 17 in

C++-POJ2777-Count Color[线段树][lazy标记][区间修改]

1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 const int MAXN=1e5+10; 5 struct node{int l,r,lazy,color;}t[MAXN*4]; 6 int L,R,C,n,m,q; 7 #define ls t[x].l 8 #define rs t[x].r 9 int count(int x){int ans=0;for(;x;x>>=1)

题解报告:hdu 1698 Just a Hook(线段树lazy标记的运用)

Problem Description In the game of DotA, Pudge's meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length.Now Pudge wants to do some operations on th

HDU 1698 Just a Hook (线段树延迟标记(lazy))

题意:有n个数初始值都为1,m个操作a,b,c,表示把区间[a,b]变为c,求最后n个数的和. 经典区间更新求和问题,需要用到延迟标记(或者说是懒惰标记),简单老说就是每次更新 的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新或询问的时候. #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #include<cm