【Luogu】P2801教主的魔法(分块)
激动qwq。这是我A的第一道分块。
分块之后对块内元素暴力sort。修改的时候对于整块打个标记,查询的时候只需要查C-tag就行了
对于非整块,暴力修改,改完之后sort
对于查询……非整块暴力查询,整块二分C-tag的位置就好啦
#include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> #include<cctype> #include<cmath> #define maxn 1000010 #define sqtn 1200 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } struct Node{ int dat,id; bool operator <(const Node a)const{ return dat<a.dat; } }; struct Block{ Node q[sqtn]; int tag,tot; Block(){memset(q,0,sizeof(q)); tag=tot=0; } }que[sqtn]; int d[maxn]; int s[maxn]; int w[maxn]; int le[sqtn],ri[sqtn]; void sorten(int x){ Block &o=que[x]; sort(o.q+1,o.q+o.tot+1); for(int i=1;i<=o.tot;++i){ w[o.q[i].id]=i; } } int main(){ int n=read(),m=read(); int sqt=sqrt(n),blo=0; for(int i=1;i<=n;++i){ d[i]=read(); s[i]=(i-1)/sqt+1; if(s[i]>blo) blo=s[i]; ri[s[i]]=i; } for(int i=n;i>=1;--i){ le[s[i]]=i; que[s[i]].q[++que[s[i]].tot]=(Node){d[i],i}; } for(int i=1;i<=blo;++i) sorten(i); for(int i=1;i<=m;++i){ char c[10];int x,y,z; scanf("%s%d%d%d",c,&x,&y,&z); if(c[0]=='M'){ int to=min(ri[s[x]],y); for(int j=x;j<=to;++j) que[s[x]].q[w[j]].dat+=z; sorten(s[x]); if(s[x]==s[y]) continue; int from=max(le[s[y]],x); for(int j=from;j<=y;++j) que[s[y]].q[w[j]].dat+=z; sorten(s[y]); for(int j=s[x]+1;j<s[y];++j) que[j].tag+=z; } else if(c[0]=='A'){ int to=min(ri[s[x]],y),ans=0; for(int j=x;j<=to;++j) if(que[s[x]].q[w[j]].dat>=z) ans++; if(s[x]==s[y]){ printf("%d\n",ans); continue; } int from=max(le[s[y]],x); for(int j=from;j<=y;++j){ //printf("%d\n",que[s[y]].q[w[j]].dat); if(que[s[y]].q[w[j]].dat>=z) ans++; } for(int j=s[x]+1;j<s[y];++j){ Block now=que[j]; int l=1,r=now.tot,lim=r+1; while(l<=r){ int mid=(l+r)>>1; if(now.q[mid].dat>=z-now.tag){ lim=mid; r=mid-1; } else l=mid+1; } ans+=now.tot-lim+1; } printf("%d\n",ans); } } return 0; } /* 5 3 1 2 3 4 5 A 1 5 4 M 3 5 1 A 1 5 4 */