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,解除这个三角形的时候就要把它的贡献一并解除掉。显然贡献就是区间长。

所以这个数据结构可以叫做“LD三角形区间修改前缀和”

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

inline ll read() {
    ll x = 0;
    bool 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;
}

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

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

/*---  ---*/

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

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

inline void update2(int l, int r) {
    df2[l]+=1;
    df2[r+1]-=1;
    df1[r+1]-=(r-l+1);
}

inline ll calc() {
    ll ans=0;
    int curd=0;
    ll curs=0;
    for(int i=1;i<=MAXM;i++){
        curd+=df2[i];
        curs+=curd;
        curs+=df1[i];
        if(curs>ans)
            ans=curs;
    }
    return ans;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
    //freopen("Yinku.out","w",stdout);
#endif // Yinku
    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);
        }
    }
    write(calc());
}

要是少一个数量级其实可以线段树:

#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 a[MAXM + 5];
ll lazy[(MAXM << 2) + 5];
int lazy2[(MAXM << 2) + 5];

inline void push_down(int o, int l, int r) {
    if(lazy[o] || lazy2[o]) {
        lazy[o << 1] += lazy[o];
        lazy[o << 1 | 1] += lazy[o];
        int m = (l + r) >> 1;
        lazy2[o << 1] += lazy2[o];
        lazy2[o << 1 | 1] += lazy2[o];
        lazy[o << 1 | 1] += (m - l + 1) * lazy2[o];
        lazy[o] = 0;
        lazy2[o] = 0;
    }
}

void build() {
    memset(a, 0, sizeof(a));
    memset(lazy, 0, sizeof(lazy));
    memset(lazy2, 0, sizeof(lazy2));
}

void update(int o, int l, int r, int a, int b, ll v) {
    if(a <= l && r <= b) {
        lazy[o] += v;
        return;
    } else {
        push_down(o, l, r);
        int m = (l + r) >> 1;
        if(a <= m)
            update(o << 1, l, m, a, b, v);
        if(b >= m + 1)
            update(o << 1 | 1, m + 1, r, a, b, v);
    }
}

void update2(int o, int l, int r, int a, int b, int h) {
    //这个区间底下包含一个高为h的矩形然后上面是一个三角形,最左侧恰好有h+1个方块
    if(a <= l && r <= b) {
        lazy[o] += h;
        lazy2[o]++;
        return;
    } else {
        push_down(o, l, r);
        int m = (l + r) >> 1;
        if(a <= m)
            update2(o << 1, l, m, a, b, h);
        //左侧底下方块是一样的
        if(b >= m + 1)
            update2(o << 1 | 1, m + 1, r, a, b, h + m - a + 1);
        //右侧多m-a+1个方块
    }
}

void all_pushdown(int o, int l, int r) {
    if(l == r) {
        a[l] += lazy[o] + lazy2[o];
    } else {
        push_down(o, l, r);
        int m = (l + r) >> 1;
        all_pushdown(o << 1, l, m);
        all_pushdown(o << 1 | 1, m + 1, r);
    }
}

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(1,1,1000000,l,r,x);
        }
        else{
            update2(1,1,1000000,l,r,0);
        }
    }
    all_pushdown(1,1,1000000);
    ll maxans=a[1];
    for(int i=2;i<=1000000;i++){
        if(a[i]>maxans)
            maxans=a[i];
    }
    printf("%lld\n",maxans);
}
posted @ 2019-06-23 17:14  韵意  阅读(289)  评论(0编辑  收藏  举报