$N$ 太大了主席树过不了
考虑分块
对每个块内的元素排序,询问就对大块二分查找,对两边小的部分暴力枚举
修改时维护 $add[i]$ 标记,维护当前块内整块已经加的数
那么整块的就直接修改 $add$ ,两边小的部分就把那两个的块暴力修改然后重新排序
然后注意一下边界就完了
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; typedef long long ll; 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<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=2e6+7,M=2e3+7,INF=1e9+7; int n,m; int a[N]; int bel[N],L[M];//bel[i]存位置i所在的块,L[i]存第i个块的左端点 int blk[M][M],tmp[M],add[M];//blk就是分出来的块排序后的东西 inline void change(int l,int r,int k)//修改 { if(bel[l]==bel[r])//要特判只有小块的情况 { int tot=0,be=bel[l]; for(int i=L[be];i<l;i++) tmp[++tot]=a[i];//把数直接扔到tmp里 for(int i=l;i<=r;i++) a[i]+=k,tmp[++tot]=a[i];//有修改要修改a[i] for(int i=r+1;i<L[be+1];i++) tmp[++tot]=a[i]; sort(tmp+1,tmp+tot+1); memcpy(blk[be],tmp,sizeof(tmp));//排序后扔给blk } int pl=bel[l-1]+1,pr=bel[r+1]-1,tot=0;//找到整块 for(int i=pl;i<=pr;i++) add[i]+=k; if(pl>bel[1])//处理左边小块 { for(int i=L[pl-1];i<l;i++) tmp[++tot]=a[i]; for(int i=l;i<L[pl];i++) a[i]+=k,tmp[++tot]=a[i]; sort(tmp+1,tmp+tot+1); memcpy(blk[pl-1],tmp,sizeof(tmp)); } if(pr<bel[n])//右边 { for(int i=L[pr+1];i<=r;i++) a[i]+=k,tmp[++tot]=a[i]; for(int i=r+1;i<L[pr+2];i++) tmp[++tot]=a[i]; sort(tmp+1,tmp+tot+1); memcpy(blk[pr+1],tmp,sizeof(tmp)); } } inline int query(int l,int r,int k)//处理询问 { if(bel[l]==bel[r])//特判没有整块 { int res=0; for(int i=l;i<=r;i++) if(a[i]>=k-add[bel[i]]) res++; return res; } int pl=bel[l-1]+1,pr=bel[r+1]-1,res=0; for(int i=pl;i<=pr;i++)//对大块的二分 res+=(L[i+1]-L[i]) -( lower_bound(blk[i]+1 , blk[i]+(L[i+1]-L[i])+1 , k-add[i]) -blk[i])+1; for(int i=l;i<L[pl];i++) if(a[i]>=k-add[bel[i]]) res++;//剩下的暴力计算 for(int i=L[pr+1];i<=r;i++) if(a[i]>=k-add[bel[i]]) res++; return res; } int main() { n=read(),m=read(); int t=sqrt(n); for(int i=1;i<=n;i++) { bel[i]=(i-1)/t+1; if(bel[i]!=bel[i-1]) L[bel[i]]=i; else L[bel[i]]=L[bel[i-1]]; a[i]=read(); } bel[n+1]=bel[n]+1; L[bel[n+1]]=n+1;//注意可能会访问到n+1 for(int i=1;i<=bel[n];i++)//预处理blk { int tot=0; for(int j=L[i];j<L[i+1];j++) tmp[++tot]=a[j]; sort(tmp+1,tmp+tot+1); memcpy(blk[i],tmp,sizeof(tmp)); } char s[7]; int x,y,z; while(m--) { scanf("%s",s); x=read(),y=read(),z=read(); if(s[0]=='M') change(x,y,z); else printf("%d ",query(x,y,z)); } return 0; }