zoukankan      html  css  js  c++  java
  • BZOJ3155:Preprefix sum——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=3155

    最朴素的想法是两棵树状数组,一个记录前缀和,一个记录前缀前缀和,但是第二个我们非常不好修改

    但其实我们发现$SS_i=i*a1+(i-1)*a2+…+ai$,我们可以试图构造这样的“类等差”数列,这样我们就可以通过加加减减就能做了。

    为了照顾最后一位的查询,我们就维护$(n-i+1)*ai$吧!

    于是我们修改就变成了两个单点修改了,查询也就是很简单了,$qry(x,1)-qry(x,0)*(n-x)$(前一个是第二棵树状数组,后面的是第一棵)。

    #include<map>
    #include<cmath>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    int a[N],n,m;
    ll tr[N][2];
    inline int lowbit(int t){return t&-t;}
    inline void add(int x,ll y,int on){
        for(int i=x;i<=n;i+=lowbit(i))tr[i][on]+=y;
    }
    inline ll qry(int x,int on){
        ll res=0;
        for(int i=x;i;i-=lowbit(i))res+=tr[i][on];
        return res;
    }
    int main(){
        n=read(),m=read();
        for(int i=1;i<=n;i++){
        add(i,a[i]=read(),0);
        add(i,(ll)(n-i+1)*a[i],1);
        }
        while(m--){
        char ch[10];
        scanf("%s",ch);
        if(ch[0]=='Q'){
            int x=read();
            printf("%lld
    ",qry(x,1)-qry(x,0)*(n-x));
        }else{
            int x=read(),y=read();
            add(x,y-a[x],0);
            add(x,(ll)(n-x+1)*(y-a[x]),1);
            a[x]=y;
        }
        }
        return 0;
    }
  • 相关阅读:
    emqttd的启动脚本
    vue2的全局变量
    windows 上优雅的安装 node 和 npm
    Intent数据清理
    android 滑动刷新的实验总结
    Android 音量键拦截
    多进程通讯笔记 android aidl
    perl-Thread-Queue for openwrt
    openwrt的编译环境
    高德地图白屏的问题
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9216417.html
Copyright © 2011-2022 走看看