zoukankan      html  css  js  c++  java
  • GXU

    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('
    ');
    }
    
    /*---  ---*/
    
    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('
    ');
    }
    
    /*---  ---*/
    
    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
    ",maxans);
    }
    
  • 相关阅读:
    编译KlayGE所需要的第三方库和工具下载
    KlayGE启用顶级域名
    Sophus和Eigen 李群李代数 简单介绍
    G2O曲线拟合1
    梯度下降
    PCL1.8单张图点云转换显示
    双目测距demo
    Kinect基于微软SDK彩图与深度图对齐
    单例模式
    zendstudio卡死
  • 原文地址:https://www.cnblogs.com/Yinku/p/11073411.html
Copyright © 2011-2022 走看看