牛客oj 小C的棋王之路(暴力分块+块重构)

传送门
那场WA了12发还是过不去.主要是区间赋值的操作想复杂了.分享一下遇到的问题.
考虑题目给的几个操作:
1.区间加 区间乘 这两个没什么难度,乘的时候把块里面加法标记也乘一下就好了.
2 区间赋值 这个其实可以用上面两个操作推导出来,不要多加一个标记去记录(速度会慢而且增大代码难度).可以乘0再加x就ok了.
3 增加一个x在尾部.这个操作可能会使最后一个块的大小太大.所以可以在这个操作超过sqrt(n)的时候重构一下块.这个次数一次是O(n)的.而且不会超过sqrt(n)次.
复杂度方面块取sqrt(n)的话总体就是O(nsqrt(n))的.题目给了3s.所以勉勉强强够用.要注意减少取模运算.两个intmax乘起来是不会爆longlongmax的.所以可以在中间的时候不取模.
代码

#pragma GCC optimize(2)
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=b;++i)
#define afir(i,a,b) for(int i=a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#include <bits/stdc++.h>
  
using namespace std;
const int N = 2e5+10;
  
inline LL read(){
    LL x = 0,f=1;char ch = getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m,blo,num,mod,pos[N];
LL L[N],R[N],sum[N],add[N],mul[N],a[N];
void clr(int i){
    fir(j,L[i],R[i]) a[j] = (a[j]*mul[i]+ add[i])%mod;
    sum[i] = (sum[i]*mul[i]+(R[i]-L[i]+1)*add[i])%mod;
    add[i] = 0;mul[i] = 1;
}
bool f = 0;
void build(){
    if(f){
        fir(i,1,num){
            clr(i);
        }
    }
    blo = sqrt(n);
    num = n/blo;
    fir(i,1,num){
        L[i] = (i-1)*blo+1;
        R[i] = i*blo;
    }
    if(n % blo){
        num++;
        L[num] = R[num-1]+1;
        R[num] = n;
    }
    if(!f){
        f = 1;
        fir(i,1,N-1) add[i] = 0,sum[i] = 0,mul[i] = 1;
        fir(i,1,num){
            sum[i] = 0;add[i] = 0;mul[i] = 1;
            fir(j,L[i],R[i]){
                sum[i] = (sum[i] + a[j])%mod;
                pos[j] = i;
            }
        }
        return;
    }
    fir(i,1,num){
        sum[i] = 0;add[i] = 0;mul[i] = 1;
        fir(j,L[i],R[i]){
            sum[i] = (sum[i] + a[j])%mod;
            pos[j] = i;
        }
    }
}
void Add(int l,int r,LL v){
    int p = pos[l],q = pos[r];
    if(p == q){
        clr(p);
        fir(i,l,r) a[i] = (a[i] + v)%mod,sum[p] = (sum[p]+v)%mod;
    }
    else{
        fir(i,p+1,q-1){
            add[i] = (add[i] + v)%mod;
        }
        clr(p);
        fir(i,l,R[p]) a[i] = (a[i] + v)%mod;
        sum[p] = (sum[p] + (R[p]-l+1)*v)%mod;
        clr(q);
        fir(i,L[q],r) a[i] = (a[i] + v)%mod;
        sum[q] = (sum[q] + (r-L[q]+1)*v)%mod;
    }
}
void Mul(int l,int r,LL v){
    int p = pos[l],q = pos[r];
    if(p == q){
        clr(p);
        fir(i,l,r){
            sum[p] = (sum[p]-a[i]+mod)%mod;
            a[i] = a[i]*v%mod;
            sum[p] = (sum[p]+a[i])%mod;
        }
    }
    else{
        fir(i,p+1,q-1){
            mul[i] = (mul[i]*v)%mod,add[i] = add[i]*v%mod;
        }
        clr(p);
        fir(i,l,R[p]){
            sum[p] = (sum[p]-a[i]+mod)%mod;
            a[i] = a[i]*v%mod;
            sum[p] = (sum[p]+a[i])%mod;
        }
        clr(q);
        fir(i,L[q],r){
            sum[q] = (sum[q]-a[i]+mod)%mod;
            a[i] = a[i]*v%mod;
            sum[q] = (sum[q]+a[i])%mod;
        }
    }
}
LL query(int l,int r){
    int p = pos[l],q = pos[r];
    LL res = 0;
    if(p == q){
        clr(p);
        fir(i,l,r){
            res = (res + a[i])%mod;
        }
    }
    else{
        fir(i,p+1,q-1){;
            res = (res + sum[i]*mul[i] + (R[i]-L[i]+1)*add[i])%mod;
        }
        clr(p);
        fir(i,l,R[p]){
            res = (res + a[i])%mod;
        }
        clr(q);
        fir(i,L[q],r){
            res = (res + a[i])%mod;
        }
    }
    return res;
}
int main(){
    n = read(); m = read(); mod = read();
    fir(i,1,n) a[i] = read();
    build();
    int cnt = 0;
    while(m--){
        int op,l,r,x;
        cin >> op;
        if(op <= 3){
            l = read(); r =read(); x= read();
            if(op == 1) Add(l,r,x);
            else if(op == 2) Mul(l,r,x);
            else{
            	Mul(l,r,0);
            	Add(l,r,x);
            }
        }
        else if(op == 4){
            cnt++;
            x = read();
            a[++n] = x;
            clr(num);
            R[num]++;
            sum[num] = (sum[num]+x)%mod;
            pos[n] = num;
            if(cnt > blo){
                build();
                cnt = 0;
            }
        }
        else{
            l = read(); r = read();
            printf("%lld\n",query(l,r));
        }
    }
      
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45590210/article/details/106191100