「CF444C」DZY Loves Colors【分块】

题目连接

题意

  • 就是开始有一个数组 a a a,开始有 ∀ i ∈ [ 1 , n ] , a i = i \forall i \in [1,n], a_i=i i[1,n],ai=i,还有另一个数组 b b b,开始有 ∀ i ∈ [ 1 , n ] , b i = 0 \forall i \in [1,n], b_i=0 i[1,n],bi=0,初始化然后两种操作,第一种操作是先对于 ∀ i ∈ [ l , r ] \forall i \in [l,r] i[l,r],令 b [ i ] = b [ i ] + ∣ x − a [ i ] ∣ b[i]=b[i]+|x-a[i]| b[i]=b[i]+xa[i],然后将 [ l , r ] [l,r] [l,r]内的所有 a a a数组的数变成 x x x,第二种操作查询 b b b数组的区间和

题解

  • 神奇的分块,对于 a a a数组,每个块打上标记表示这个块内所有数是否都相同,然后对于 b b b数组,打上标记表示这个块所有位置的数都要加上多少,然后处理第一种操作的时候不完整的块暴力处理,完整的块里面如果标记一相同,那么 O ( 1 ) O(1) O(1)更新数据,否则暴力修改所有 b b b数组元素
  • 复杂度 O ( O( O(能过 ) ) )

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int smaxn=3005;
int n,m,opt,l,r,x;
namespace blocking{
    int tot,belong[maxn],siz[smaxn],block;  //分块基本数据
    long long a[maxn],same[smaxn],sum[smaxn],mark[smaxn],b[maxn];                //解题数据
    inline void init(int n) {
        block=(int)sqrt((double)n);
        tot=n%block?(n/block+1):(n/block);
        for(int i=1;i<=n;i++) belong[i]=(i-1)/block+1;
        for(int i=1;i<=tot;i++) siz[i]=(min(i*block,n)-(i-1)*block);
    }
    inline void solve(int l,int r,long long val) {
        for(int i=l;i<=r;i++) {
            if(same[belong[i]]) {
                for(int j=(belong[i]-1)*block+1;j<=belong[i]*block;j++) a[j]=same[belong[i]];
                same[belong[i]]=0;
            }
            sum[belong[i]]+=abs(val-a[i]);
            b[i]+=abs(val-a[i]);
            a[i]=val;
        }
    }
    inline void update(int l,int r,long long val) {
        if(belong[r]-belong[l]<=1) {
            solve(l,r,val);
            return;
        }
        solve(l,belong[l]*block,val);
        for(int i=belong[l]+1;i<=belong[r]-1;i++) {
            if(!same[i]) solve((i-1)*block+1,i*block,val),same[i]=val;
            else {
                mark[i]+=abs(val-same[i]);
                sum[i]+=1LL*block*abs(val-same[i]);
                same[i]=val;
            }
        }
        solve((belong[r]-1)*block+1,r,val);
    }
 
    inline long long query(int l,int r) {
        long long ans=0;
        if(belong[r]-belong[l]<=1) {
            for(int i=l;i<=r;i++) ans+=b[i]+mark[belong[i]];
            return ans;
        }
        for(int i=l;i<=belong[l]*block;i++) ans+=b[i]+mark[belong[i]];
        for(int i=belong[l]+1;i<=belong[r]-1;i++) ans+=sum[i];
        for(int i=(belong[r]-1)*block+1;i<=r;i++) ans+=b[i]+mark[belong[i]];
        return ans;
    }
 
    inline void debug() {
        printf("block= %d, tot= %d\n",block,tot);
        for(int i=1;i<=n;i++) printf("%d%c",belong[i],i==n?'\n':' ');
    }
}
using namespace blocking;
 
int main()
{
    scanf("%d %d",&n,&m);init(n);
    for(int i=1;i<=n;i++) a[i]=i;
    for(int i=1;i<=m;i++) {
        scanf("%d",&opt);
        if(opt==1) {
            scanf("%d %d %d",&l,&r,&x);
            update(l,r,x);
        }else {
            scanf("%d %d",&l,&r);
            printf("%lld\n",query(l,r));
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值