ACM-ICPC 2018 徐州赛区网络预赛 H. Ryuji doesn't want to study (线段树维护前缀和的前缀和)

题意
很简答就是每次查询 (L,R)的时候 ,查询

a [ L ] ( R L + 1 ) + a [ L + 1 ] ( R L 1 ) + a [ L + 2 ] ( R L 2 ) . . . . a [ R ] 1
,还有修改值
思路
我们可以看出
a [ l ] × L + a [ l + 1 ] × ( L 1 ) + + a [ r 1 ] × 2 + a [ r ]
这个东西其实就是前缀和的前缀和啊 。。。
a [ 1 ] + a [ 1 ] + a [ 2 ] + a [ 1 ] + a [ 2 ] + a [ 3 ] + a [ 1 ] + a [ 2 ] + a [ 3 ] + a [ 4 ] = 4 a [ 1 ] + 3 a [ 2 ] + 2 a [ 3 ] + a [ 4 ]

那么我们线段树就维护前缀和的前缀和就行了,对于查询来说,比如说我我们查
[ 4 , 6 ]
,那其实就是
a [ 4 ] + a [ 4 ] + a [ 5 ] + a [ 4 ] + a [ 5 ] + a [ 6 ] , a [ 1 ] + a [ 2 ] + a [ 3 ] + a [ 4 ] + a [ 1 ] + a [ 2 ] + a [ 3 ] + a [ 4 ] + a [ 5 ] + a [ 1 ] + a [ 2 ] + a [ 3 ] + a [ 4 ] + a [ 5 ] + a [ 6 ]
,可以看出他多了什么? 他多了
a [ 1 ] + a [ 2 ] + a [ 3 ] + a [ 1 ] + a [ 2 ] + a [ 3 ] + a [ 1 ] + a [ 2 ] + a [ 3 ]
,他多了一个
( R L + 1 ) ( a [ 1 ] + a [ 2 ] + a [ 3 ] )
,那么查询其实就是query(l,r) - (r-l+1) *query(l-1,l-1),对于更新操作怎么办?我们把第4个位置上面的值+1,那其实就是所有的a[4] + 1,就是(pos,n)的这个区间我们都+1,这就是一个裸的区间更新和区间查询
代码

#include <bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define int long long
using namespace std;
const int maxn = 1e5+10;
long long a[maxn] , sum[maxn];
long long tree[maxn<<2] ,add[maxn<<2];
struct Tree
{
    void pushup(int rt)
    {
        tree[rt] = tree[rt<<1] + tree[rt<<1|1];
    }
    void pushdown(int l,int r,int rt)
    {
        if(!add[rt]) return ;
        int m = (l+r)>>1;
        add[rt<<1] += add[rt];
        add[rt<<1|1] += add[rt];
        tree[rt<<1] += add[rt] *(m-l+1);
        tree[rt<<1|1] += add[rt] * (r-m);
        add[rt] = 0;
    }
    void build(int l,int r,int rt)
    {

        if(l == r) {tree[rt] = sum[l] ; return ;}
        int m = (l+r)>>1;
        build(lson);
        build(rson);
        pushup(rt);
    }
    void update(int L,int R,long long val, int l,int r,int rt)
    {
        if(l >= L && R >= r)
        {
            tree[rt] += (r-l+1)*val;
            add[rt] += val;
            return ;
        }
        pushdown(l,r,rt);
        int m = (l+r)>>1;
        if(m >= L) update(L,R,val,lson);
        if(m < R) update(L,R,val,rson);
        pushup(rt);
    }
    long long query(int L,int R,int l,int r,int rt)
    {
        if(l >= L && R >= r) return tree[rt];
        pushdown(l,r,rt);
        int m = (l+r)>>1;
        long long ret = 0 ;
        if(m >= L) ret += query(L,R,lson);
        if(m < R) ret += query(L,R,rson);
        return ret;
    }
};
signed main()
{
    int n,q;
    while(scanf("%lld%lld",&n,&q)!=EOF)
    {
        memset(sum,0,sizeof(sum));
        memset(tree,0,sizeof(tree));
        memset(add,0,sizeof(add));
        sum[0] = 0;
        Tree A;
        for(int i = 1 ; i <= n ; i++)
        {
            scanf("%lld",&a[i]);
            sum[i] = sum[i-1] + a[i];
        }
        A.build(1,n,1);
        while(q--)
        {
            int op,l,r;
            scanf("%lld%lld%lld",&op,&l,&r);
            if(op == 1)
            {
                long long ans = 0;
                if(l == 1) ans = A.query(l,r,1,n,1);
                else
                {
                    ans = A.query(l,r,1,n,1) - (r-l+1) * A.query(l-1,l-1,1,n,1);
                }
                cout<<ans<<endl;
            }
            else
            {
                A.update(l,n,r-a[l],1,n,1);
                a[l] = r;
            }
        }
    }

}

猜你喜欢

转载自blog.csdn.net/wjmwsgj/article/details/82695131
今日推荐