zoukankan      html  css  js  c++  java
  • 分块+lazy 或者 线段树+lazy Codeforces Round #254 (Div. 2) E

    E. DZY Loves Colors
    time limit per test
    2 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    DZY loves colors, and he enjoys painting.

    On a colorful day, DZY gets a colorful ribbon, which consists of n units (they are numbered from 1 to n from left to right). The color of the i-th unit of the ribbon is i at first. It is colorful enough, but we still consider that the colorfulness of each unit is 0 at first.

    DZY loves painting, we know. He takes up a paintbrush with color x and uses it to draw a line on the ribbon. In such a case some contiguous units are painted. Imagine that the color of unit i currently is y. When it is painted by this paintbrush, the color of the unit becomes x, and the colorfulness of the unit increases by |x - y|.

    DZY wants to perform m operations, each operation can be one of the following:

    1. Paint all the units with numbers between l and r (both inclusive) with color x.
    2. Ask the sum of colorfulness of the units between l and r (both inclusive).

    Can you help DZY?

    Input

    The first line contains two space-separated integers n, m (1 ≤ n, m ≤ 105).

    Each of the next m lines begins with a integer type (1 ≤ type ≤ 2), which represents the type of this operation.

    If type = 1, there will be 3 more integers l, r, x (1 ≤ l ≤ r ≤ n; 1 ≤ x ≤ 108) in this line, describing an operation 1.

    If type = 2, there will be 2 more integers l, r (1 ≤ l ≤ r ≤ n) in this line, describing an operation 2.

    Output

    For each operation 2, print a line containing the answer — sum of colorfulness.

    Examples
    input
    3 3
    1 1 2 4
    1 2 3 5
    2 1 3
    output
    8
    input
    3 4
    1 1 3 4
    2 1 1
    2 2 2
    2 3 3
    output
    3
    2
    1
    input
    10 6
    1 1 5 3
    1 2 7 9
    1 10 10 11
    1 3 8 12
    1 1 10 3
    2 1 10
    output
    129
    Note

    In the first sample, the color of each unit is initially [1, 2, 3], and the colorfulness is [0, 0, 0].

    After the first operation, colors become [4, 4, 3], colorfulness become [3, 2, 0].

    After the second operation, colors become [4, 5, 5], colorfulness become [3, 3, 2].

    So the answer to the only operation of type 2 is 8.

    题意

    一开始,a[i]=i,b[i]=0,然后有两个操作:

    1.使得[l,r]的b[i]+=fabs(x-a[i]),a[i]=x

    2.查询[l,r]的b[i]和

    思路一线段树+lazy

    这个应该比较轻松吧,线段树的lazy大家应该都会,这里我就不多说了。

    思路二:分块+lazy

    终于感觉到卿学姐之前的分块写法的漏洞了——代码量大,虽然思路清晰,但是很容易错TAT,我debug了1个小时多。

    这里的关键就是如何学习lazy技巧了。

    刚开始的时候我的lazy就直接保存之前输入的val,就和线段树一样那个样子更新,但是最后我写着写着发现,代码量好像有点大啊,就果断看了一下卿学姐的代码,瞬间感觉自己好傻。

    这里,我们用lastval表示之前该块里面的所有的a[i]更新以后的权值,然后lazy就表示如果是重复更新的话,那么lazy[i] += abs(val - lastval[i])即可,然后这里我们再用一个sum保存整个块的val。

    当询问左右区间的时候,就直接暴力即可:ans += lazy[j] + b[j],当询问中间区间(即块)的时候,就是ans+=sum[j]

    我的代码:按照卿学姐以前的习惯写的

    //看看会不会爆int!数组会不会少了一维!
    //取物问题一定要小心先手胜利的条件
    #include <bits/stdc++.h>
    using namespace std;
    #pragma comment(linker,"/STACK:102400000,102400000")
    #define LL long long
    #define ALL(a) a.begin(), a.end()
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    #define haha printf("haha
    ")
    const int maxn = 1e5 + 5;
    LL a[maxn], b[maxn], add[maxn], sum[maxn], lazy[maxn], lastval[maxn];
    int block, num, belong[maxn], l[maxn], r[maxn];
    int n, m;
    
    void build(){
        block = sqrt(n); num = n / block;
        if (n % block) num++;
        for (int i = 1; i <= num; i++)
            l[i] = (i - 1) * block + 1, r[i] = i * block;
        for (int i = 1; i <= n; i++)
            belong[i] = (i - 1) / block + 1;
    }
    
    ///如果lazy保存的是目前要更新的值x,那么代码的复杂度就会大大增加
    ///如果lazy保存的是x减pre_lazy_val,那么代码的复杂度就会大大减少,但是会多一个空间
    ///叫做lastval,表示保存之前的val
    void update(int x, int y, int val){
        if(belong[x] == belong[y]){
            if (lastval[belong[x]]){
                for (int i = l[belong[x]]; i <= r[belong[x]]; i++) a[i] = lastval[belong[x]];
                lastval[belong[x]] = 0;
            }
            for (int i = x; i <= y; i++){
                b[i] += abs(val - a[i]); sum[belong[x]] += abs(val - a[i]);
                a[i] = val;
            }
            return ;
        }
        ///对x的修改
        if (lastval[belong[x]]){
            for (int i = l[belong[x]]; i <= r[belong[x]]; i++) a[i] = lastval[belong[x]];
            lastval[belong[x]] = 0;
        }
        for (int i = x; i <= r[belong[x]]; i++){
            b[i] += abs(val - a[i]); sum[belong[x]] += abs(val - a[i]);
            a[i] = val;
        }
        ///对y的修改
        if (lastval[belong[y]]){
            for (int i = l[belong[y]]; i <= r[belong[y]]; i++) a[i] = lastval[belong[y]];
            lastval[belong[y]] = 0;
        }
        for (int i = l[belong[y]]; i <= y; i++){
            b[i] += abs(val - a[i]); sum[belong[y]] += abs(val - a[i]);
            a[i] = val;
        }
    
        ///对块的修改
        for (int i = belong[x] + 1; i < belong[y]; i++){
            if (lastval[i]){
                lazy[i] += abs(val - lastval[i]);
                sum[i] += 1LL * (r[i] - l[i] + 1) * abs(val - lastval[i]);
                lastval[i] = val;
            }
            else {
                for (int j = l[i]; j <= r[i]; j++){
                    b[j] += abs(val - a[j]);
                    sum[i] += abs(val - a[j]);
                    a[j] = val;//////////////这里增加了
                }
                lastval[i] = val;
            }
        }
    }
    
    LL query(int x, int y){
        LL ans = 0;
        if (belong[x] == belong[y]){
            for (int i = x; i <= y; i++) ans += b[i] + lazy[belong[x]];
            return ans;
        }
        ///对x进行操作
        for (int i = x; i <= r[belong[x]]; i++)
            ans += b[i] + lazy[belong[x]];
    
        ///对y进行操作
        for (int i = l[belong[y]]; i <= y; i++)
            ans += b[i] + lazy[belong[y]];
    
        ///对块进行操作
        for (int i = belong[x] + 1; i < belong[y]; i++)
            ans += sum[i];
        return ans;
    }
    
    int main(){
        cin >> n >> m;
        for (int i = 1; i <= n; i++) a[i] = i;
        build();
        for (int i = 1; i <= m; i++){
            int ty, x, y, z;
            scanf("%d", &ty);
            if (ty == 1){
                scanf("%d%d%d", &x, &y, &z);
                update(x, y, z);
            }
            if (ty == 2){
                scanf("%d%d", &x, &y);
                printf("%lld
    ", query(x, y));
            }
        }
        return 0;
    }
    /*
    10 10
    1 1 5 3
    2 1 10
    1 2 7 9
    2 1 10
    1 10 10 11
    2 1 10
    1 3 8 12
    2 1 10
    1 1 10 3
    2 1 10
    */
    View Code

    写完了以后我就发现自己太年轻了,果然分块还能写的更加简便啊= =。 来自:链接

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define lowbit(x) ((x)&(-x))
    const int maxn = 1e5 + 500;
    
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    
    int n , m , unit , a[maxn] ;
    long long extra[maxn] , lz[maxn] , ls[maxn] , b[maxn];
    
    int main(){
        n = read() , m = read();
        unit = sqrt( n );
        for(int i = 0 ; i < n ; ++ i) a[i] = i + 1;
        while( m -- ){
            int op = read() , l = read() , r = read() , x;
            --l;
            --r;
            if( op == 1 ){
                x = read();
                for(int i = l ; i <= r ; ){
                    int idx = i / unit;
                    int st = idx * unit;//表示目前块的左端点,但是要注意,这里没有+1
                    int ed = min( n , (idx + 1) * unit );//表示目前块的右端点
                    if(i == st && r >= ed - 1){
                        if( ls[idx] ){
                            extra[idx] += 1LL * abs(x - ls[idx]) * (ed - st) ;
                            lz[idx] += abs(x - ls[idx]);
                            ls[idx] = x;
                        }
                        else{
                            for(int j = st; j < ed; ++j){
                                b[j] += abs(a[j] - x );
                                extra[idx] += abs(a[j] - x);
                                a[j] = x;
                            }
                            ls[idx] = x;
                        }
                        i = ed;
                    }
                    else{///对于块的两端东西进行暴力
                        if(ls[idx]){
                            for(int j = st; j < ed; ++j) a[j] = ls[idx];
                            ls[idx] = 0;
                        }
                        extra[idx] += abs(a[i] - x);
                        b[i] += abs(a[i] - x);
                        a[i] = x;
                        ++i;
                    }
                }
            }else{
                long long res = 0;
                for(int i = l; i <= r ;){//对于中间,全都保存在extra当中?
                    int idx = i / unit;
                    int st = idx * unit;
                    int ed = min(n, (idx + 1) * unit);
                    if(i == st && r >= ed - 1){
                        res += extra[idx];
                        i = ed;
                    }else{///对于两端进行暴力
                        res += b[i] + lz[idx];
                        ++i;
                    }
                }
                printf("%lld
    " , res);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    BZOJ1293: [SCOI2009]生日礼物
    BZOJ2326: [HNOI2011]数学作业
    BZOJ1179: [Apio2009]Atm
    树链剖分的一个小细节
    BZOJ1146: [CTSC2008]网络管理Network
    BZOJ1984: 月下“毛景树”
    BZOJ3196: Tyvj 1730 二逼平衡树
    BZOJ1579: [Usaco2009 Feb]Revamping Trails 道路升级
    BZOJ1674: [Usaco2005]Part Acquisition
    Babel 在浏览器环境使用方法
  • 原文地址:https://www.cnblogs.com/heimao5027/p/6533044.html
Copyright © 2011-2022 走看看