题解 | 《算法竞赛进阶指南》一个简单的整数问题

【题目】

You have N integers, A 1 , A 2 , . . . , A N A_1,A_2,...,A_N .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.

【题意】

有N个数,会给初始值。然后两种操作,一个更新操作,一个查询操作。更新操作为增加 [ a , b ] [a,b] 区间内每个数c值,查询操作则是查询 [ a , b ] [a,b] 区间内数的总和,然后输出。

【题解】

有两种显而易见的解法,一种是树状数组,一种线段树,这里说一下逻辑简单点的线段树解法。这种纯的区间查询和区间更新,就是一道裸的线段树。在这里就说一下线段树节省时间开支的核心之一的思想Lazy思想,在线段树中称之为懒标记。懒标记的使用真的是突出顺便二字,也就是每次更新的时候,不更新到最底部,而是更新到被更新区间完成覆盖的区间,更新好当前区间同时,也给自己做一个标记,比如说这个区间内的值都+3,那这个标记就+3。然后下次查询或者更新的时候,又遇到了这个区间,那么就对自己的左儿子和右儿子(线段树是一个平衡二叉树)进行更新标记的值的操作,并且让儿子们继承自己的标记。以方便到时候查到儿子的时候,继承给孙子们。总的就是一种既然能顺便把这东西做了,那就做一下好了,可以从这个思想中感受到一股浓厚的的气息。

时间复杂度:线段树的建树复杂度 O ( N ) O(N) ,查询复杂度 O ( l o g N ) O(logN) ,更新复杂度 O ( l o g N ) O(logN) ,此题整体复杂度 O ( M l o g N ) O(MlogN)

#include<iostream>
#include<cstring>
#include<sstream>
#include<string>
#include<cstdio>
#include<cctype>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<list>
#include<set>
#include<map>
#include<algorithm>
#define fi first
#define se second
#define MP make_pair
#define P pair<int,int>
#define PLL pair<ll,ll>
#define Sca(x) scanf("%d",&x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x)
#define Scl2(x,y) scanf("%lld%lld",&x,&y)
#define Scl3(x,y,z) scanf("%lld%lld%lld",&x,&y,&z)
#define Pri(x) printf("%d\n",x)
#define Prl(x) printf("%lld\n",x)
#define For(i,x,y) for(int i=x;i<=y;i++)
#define _For(i,x,y) for(int i=x;i>=y;i--)
#define FAST_IO std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long
const int INF=0x3f3f3f3f;
const ll INFL=0x3f3f3f3f3f3f3f3f;
const double Pi = acos(-1.0);
using namespace std;
template <class T>void tomax(T&a,T b){ a=max(a,b); } 
template <class T>void tomin(T&a,T b){ a=min(a,b); }
const int N=1e5+5;
struct Segt{
    #define lc (p<<1)
    #define rc (p<<1|1)
    #define MID (tree[p].l+tree[p].r)>>1
    struct Tree{
        int l,r;
        ll val,lz;
        void updata(ll num){
            val+=num*(r-l+1);
            lz+=num;
        }
    }tree[N<<2];
    void pushdown(int p){ tree[p].val=tree[lc].val+tree[rc].val; }
    void pushup(int p){
        tree[lc].updata(tree[p].lz);
        tree[rc].updata(tree[p].lz);
        tree[p].lz=0;
    }
    void build(int l,int r,int p){
        tree[p]=Tree{l,r,0,0};
        if(l==r){ Scl(tree[p].val); return ; }
        int mid=MID;
        build(l,mid,lc);
        build(mid+1,r,rc);
        pushdown(p);
    }
    void updata(int l,int r,int p,ll val){
        if(tree[p].l>=l&&tree[p].r<=r){
            tree[p].updata(val);
            return ;
        }
        if(tree[p].lz) pushup(p);
        int mid=MID;
        if(l<=mid) updata(l,r,lc,val);
        if(r>mid) updata(l,r,rc,val);
        pushdown(p);
    }
    ll getans(int l,int r,int p){
        if(tree[p].l>=l&&tree[p].r<=r) return tree[p].val;
        ll ans=0;
        if(tree[p].lz) pushup(p);
        int mid=MID;
        if(l<=mid) ans+=getans(l,r,lc);
        if(r>mid) ans+=getans(l,r,rc);
        return ans;
    }
}t;
int main(){
    int n,m;
    while(~Sca2(n,m)){
        t.build(1,n,1);
        while(m--){
            char cmd; scanf(" %c",&cmd);
            if(cmd=='Q'){
                int i,j; Sca2(i,j);
                Prl(t.getans(i,j,1));
            }
            else if(cmd=='C'){
                int i,j,val;
                Sca3(i,j,val);
                t.updata(i,j,1,val);
            }
        }
    }
}
发布了39 篇原创文章 · 获赞 9 · 访问量 1960

猜你喜欢

转载自blog.csdn.net/qq_36296888/article/details/103057754