#分块,二分#洛谷 3863 序列

题目传送门


分析

单点查询的话考虑将下标和时间调转,以下标为第一维,维护每一刻对应的值,

区间加就可以差分变成单点加,只不过是给一段后缀时间区间加,由于需要查询前缀时间

不妨考虑分块,整块修改打标记,散块修改归并,查询就是整块二分,散块暴力即可


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
const int N=100011; struct rec{int z,rk;}; vector<rec>K[N];
int n,m,a[N],bl,ans[N],v[N],rk[N],rK[N],Rk[N],pos[N],L[N],R[N]; long long lazy[N],c[N];
int iut(){
    int ans=0,f=1; char c=getchar();
    while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans*f;
}
void print(int ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
int main(){
    n=iut(),m=iut(),bl=sqrt(m);
    for (int i=1;i<=n;++i) a[i]=iut();
    for (int i=0;i<=m;++i) pos[i]=i/bl;
    for (int i=0;i<=m;++i) R[pos[i]]=i;
    for (int i=m;~i;--i) L[pos[i]]=rk[i]=i;
    for (int i=1;i<=m;++i)
    if (iut()==1){
        int l=iut(),r=iut(),z=iut();
        K[l].push_back((rec){z,i});
        if (r<n) K[r+1].push_back((rec){-z,i});
    }else{
        int x=iut(),z=iut();
        K[x].push_back((rec){z,-i});
    }
    for (int x=1;x<=n;++x){
        int siz=K[x].size();
        for (int i=0;i<siz;++i)
        if (K[x][i].rk<0){
            K[x][i].rk*=-1;
            int p=pos[K[x][i].rk-1],now=0;
            for (int j=L[p];j<K[x][i].rk;++j)
            if (a[x]+c[j]+lazy[p]>=K[x][i].z) ++now;
            for (int j=0;j<p;++j){
                int l=L[j],r=R[j]+1;
                while (l<r){
                    int mid=(l+r)>>1;
                    if (a[x]+c[rk[mid]]+lazy[j]>=K[x][i].z) r=mid;
                        else l=mid+1;
                }
                now+=R[j]-r+1;
            }
            ans[K[x][i].rk]=now,v[K[x][i].rk]=1;
        }else{
            int p=pos[K[x][i].rk],i1=1,j1=1,o=L[p];
            rK[0]=Rk[0]=0;
            for (int j=L[p];j<=R[p];++j)
            if (rk[j]>=K[x][i].rk) rK[++rK[0]]=rk[j],c[rk[j]]+=K[x][i].z;
                else Rk[++Rk[0]]=rk[j];
            while (i1<=rK[0]&&j1<=Rk[0]){
                if (c[rK[i1]]<=c[Rk[j1]]) rk[o++]=rK[i1++];
                    else rk[o++]=Rk[j1++];
            }
            while (i1<=rK[0]) rk[o++]=rK[i1++];
            while (j1<=Rk[0]) rk[o++]=Rk[j1++];
            for (int j=pos[m];j>p;--j) lazy[j]+=K[x][i].z;
        }
    }
    for (int i=1;i<=m;++i) if (v[i])
        print(ans[i]),putchar(10);
    return 0;
}
posted @ 2024-02-27 23:55  lemondinosaur  阅读(5)  评论(0编辑  收藏  举报