GXU - 7D - 区间求和 - 前缀和

https://oj.gxu.edu.cn/contest/7/problem/D

描述
有一个所有元素皆为0的数组A,有两种操作:
1 l r x表示将A区间[l,r]内所有数加上x;
2 l r表示将A区间[l,r]内从左往右数第i个数加上i;

给出m个操作,请输出操作结束后A中的最大值。

输入
第一行一个整数m,表示操作的个数
接下来有m行,表示操作的内容,具体格式与题目中一致

0<=m<=10^6
1<=l<=r<=10^6
0<=x<=10^9

输出
输出一个整数,表示所有操作之后A中的最大值

思路,差分,难点在于三角形怎么处理。
其实也不难,计算一下有几个三角形在哪里出现又消失就可以了。当三角形消失的时候解除掉三角形对当前的影响就足够了。

首先对差分求前缀和可以复原原数组,这个简单。

那么对三角形数量差分求前缀和可以复原每个区间的三角形的数量。

发现每一个三角形会使得前缀和增加1,解除这个三角形的时候就要把它的贡献一并解除掉。显然贡献就是区间长。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

inline ll read() {
    ll x = 0;
    //int f = 0;
    char c;
    do {
        c = getchar();
        /*if(c == '-')
            f = 1;*/
    } while(c < '0' || c > '9');
    do {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    } while(c >= '0' && c <= '9');
    //return f ? -x : x;
    return x;
}

inline void _write(int x) {
    if(x > 9)
        _write(x / 10);
    putchar(x % 10 + '0');
}

inline void write(int x) {
    if(x < 0) {
        putchar('-');
        x = -x;
    }
    _write(x);
    putchar('\n');
}

/*---  ---*/

const int MAXM = 1000000;
ll df1[MAXM+5],df2[2][MAXM+5];

void build() {
    memset(df1, 0, sizeof(df1));
    memset(df2, 0, sizeof(df2));
}

void update(int l, int r, ll v) {
    df1[l]+=v;
    df1[r+1]-=v;
}

void update2(int l, int r) {
    df2[0][l]+=1;
    //从l位置开始一个三角形,三角形数量增加
    df2[0][r+1]-=1;
    //从r+1位置解除一个三角形
    df2[1][r+1]-=(r-l+1);
    //该三角形目前累计了区间长的数字,从这里开始解除掉
}

ll calc() {
    ll ans=0;
    ll curdelta=0;//当前的三角形数
    ll cursum=0;//当前累计的叠加量
    for(int i=1;i<=1000000;i++){
        cursum+=df1[i];
        curdelta+=df2[0][i];
        cursum+=curdelta;
        cursum+=df2[1][i];
        if(cursum>ans)
            ans=cursum;
    }
    return ans;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
    //freopen("Yinku.out","w",stdout);
#endif // Yinku
    //sieve();
    build();
    int m=read();
    while(m--){
        int op=read(),l=read(),r=read();
        if(op==1){
            int x=read();
            update(l,r,x);
        }
        else{
            update2(l,r);
        }
    }

    printf("%lld\n",calc());
}

原文地址:https://www.cnblogs.com/Yinku/p/11073411.html

时间: 2024-10-14 14:30:52

GXU - 7D - 区间求和 - 前缀和的相关文章

vijos1740 聪明的质监员 (二分、区间求和)

http://www.rqnoj.cn/problem/657 https://www.vijos.org/p/1740 P1740聪明的质检员 请登录后递交 标签:NOIP提高组2011[显示标签] 描述 小 T 是一名质量监督员,最近负责检验一批矿产的质量.这批矿产共有n个矿石,从1到n逐一编号,每个矿石都有自己的重量wi以及价值vi.检验矿产的流程是: 1.给定m个区间[Li,Ri]: 2.选出一个参数W: 3.对于一个区间[Li,Ri],计算矿石在这个区间上的检验值Yi: Yi = ∑1

区间求和

区间求和 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 LYK在研究一个有趣的东西. 假如有一个长度为n的序列,那么这个序列的权值将是所有有序二元组i,j的 Σaj−ai 其中1<=i<j<=n. 但是这个问题似乎太简单了. 于是LYK想在所有有序二元组k,l中若ak=al,其中1<=k<l<=n,则将 a{k},a{k+1},...,a{l}  提出当做一个序列,计算它的权值. 并统计所有这样的区间的权值和. 由于答案可能很大,你只需要将答案对2^

非递归线段树区间修改区间求和的两种实现(以POJ 3468为例)

题意:就是一个数列,支持  查询区间和  以及  区间内的数都加上 C . 递归线段树很好写,就不讲了. 递归版本        : 内存:6500K   时间:2.6 秒 非递归版本一: 内存:4272K   时间:1.1秒 非递归版本二: 内存:4272K   时间:1.3秒 -------------------------------------------------------------------------------------------------------------

树状数组区间修改和区间求和

最一般树状数组能做到的操作是单点修改,区间求和,都是log(n)级别的.原理就是用树状数组维护a[i]的部分和. 想要做到修改区间,求单点值也很简单,用树状数组维护a[i]的差分数组d[i]的部分和既可. 那么,如何同时做到区间求和,区间修改呢? 有人可能会说了,如果是区间求和区间修改的话,直接写线段树不就好了吗? 但是,从代码长度来看(dalao请无视),显然使用树状数组在考场上出错率会小一些,而且比较爽QWQ. 回归正题.我们知道,想要达到log(n)级别的区间修改需要修改d[i],那么在修

HDU4027 Can you answer these queries 线段树区间求和+剪枝

给了你n,然后n个数字在一个数组中,接下来m个询问,每个询问三个数字 t,x,y,若t==0,那么修改区间[x,y]的每一个值,变为原来每个位置上的数 开根号取整,若t==1,那么对区间[x,y]求和 由于n,m,很大,所以树状数组铁定超时,若直接用线段树来做区间修改,那么也是超时,这类题目没别的方法了,静心剪枝,发现题目给的数据范围为2^63,有没有发现,2^63开根号 绝对不需要开10次,就能到1,到1以后就不需要再开了,意思就是若有某个区间[x,y]每一个点的值都为1时,这一段区间事实上是

【线段树(单点修改,区间求和)】HDU1166 - 敌军布阵

hdu1166 敌兵布阵,单点修改,区间求和. [ATTENTION]MAXN要开成节点数的4倍,开得不够会提示TLE. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define lson l,m,root<<1 5 #define rson m+1,r,root<<1|1 6 using namespace std; 7 const int MAXN=50000*

算法模板——线段树3(区间覆盖值+区间求和)

实现功能——1:区间覆盖值:2:区间求和 相比直接的区间加,这个要注重顺序,因为操作有顺序之分.所以这里面的tag应该有个pushup操作(本程序中的ext) 1 var 2 i,j,k,l,m,n,a1,a2,a3,a4:longint; 3 a,b,d:array[0..100000] of longint; 4 function max(x,y:longint):longint;inline; 5 begin 6 if x>y then max:=x else max:=y; 7 end;

算法模板——线段树4(区间加+区间乘+区间覆盖值+区间求和)

实现功能——1:区间加法 2:区间乘法 3:区间覆盖值 4:区间求和 这是个四种常见线段树功能的集合版哦...么么哒(其实只要协调好三种tag的关系并不算太难——前提是想明白了线段树的工作模式) 代码长度几经修改后也大为缩水 还有!!!——通过BZOJ1798反复的尝试,我的出来一个重要结论——尽量减少pushup操作的不必要使用次数,对于程序提速有明显的效果!!! 1 type vet=record 2 a0,a1:longint; 3 end; 4 var 5 i,j,k,l,m,n,a1,

算法模板——线段树1(区间加法+区间求和)

实现功能——1:区间加法:2:区间求和 最基础最经典的线段树模板.由于这里面操作无顺序之分,所以不需要向下pushup,直接累积即可 1 var 2 i,j,k,l,m,n,a1,a2,a3,a4:longint; 3 a,b:array[0..100000] of longint; 4 function max(x,y:longint):longint;inline; 5 begin 6 if x>y then max:=x else max:=y; 7 end; 8 function min