Description
二阶堂真红给了你一个长为 $n$ 的序列 $a$,有 $m$ 次操作
1. 把区间 $[l,r]$ 中大于 $x$ 的数减去 $x$。
2. 查询区间 $[l,r]$ 中 $x$ 的出现次数。
Solution
CF896E Welcome home, Chtholly数据增强版
缩小了空间限制,扩大了数据范围,所以必须离线下所有操作,每次只维护一个块,给所有操作更新答案
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int n,m,a[10000005],L[1000005],R[1000005],cnt=1,ll,rr,maxx,ans[1000005]; int rt[1000005],siz[1000005],tag,fa[1000005],val[1000005]; const int S=1000; struct Node { int opt,l,r,x; }node[1000005]; inline int read() { int f=1,w=0; char ch=0; while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=getchar(); return f*w; } int find(int x) { return fa[x]==x?fa[x]:fa[x]=find(fa[x]); } inline void merge(int p,int x,int y) { if(rt[y]) fa[rt[x]+(p-1)*S]=rt[y]+(p-1)*S; else rt[y]=rt[x],val[rt[y]+(p-1)*S]=y; siz[y]+=siz[x],rt[x]=siz[x]=0; } inline void maintain(int p) { maxx=tag=0; memset(siz,0,sizeof(siz)); memset(rt,0,sizeof(rt)); for(int i=ll;i<=rr;i++) { maxx=max(maxx,a[i]); if(!rt[a[i]]) fa[i]=i,rt[a[i]]=i-(p-1)*S,val[i]=a[i]; else fa[i]=rt[a[i]]+(p-1)*S; siz[a[i]]++; } } inline void updateblock(int p,int x) { if(maxx-tag>=(x<<1)) { for(int i=tag+1;i<=tag+x;i++) if(rt[i]) merge(p,i,i+x); tag+=x; } else { for(int i=maxx;i>tag+x;i--) if(rt[i]) merge(p,i,i-x); maxx=min(maxx,x+tag); } } inline void update(int p,int l,int r,int x) { for(int i=(p-1)*S+1;i<=min(n,p*S);i++) a[i]=val[find(i)],siz[a[i]]=rt[a[i]]=0,a[i]-=tag; for(int i=(p-1)*S+1;i<=min(n,p*S);i++) fa[i]=0; tag=0; for(int i=l;i<=r;i++) if(a[i]>x) a[i]-=x; maxx=tag=0; for(int i=ll;i<=rr;i++) { maxx=max(maxx,a[i]); if(!rt[a[i]]) fa[i]=i,rt[a[i]]=i-(p-1)*S,val[i]=a[i]; else fa[i]=rt[a[i]]+(p-1)*S; siz[a[i]]++; } } int main() { n=read(),m=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=m;i++) node[i]=(Node){read(),read(),read(),read()}; L[cnt]=1; while(L[cnt]+S-1<=n) R[cnt]=L[cnt]+S-1,++cnt,L[cnt]=R[cnt-1]+1; R[cnt]=n; for(int i=1;i<=cnt;i++) { ll=L[i],rr=R[i]; maintain(i); for(int j=1;j<=m;j++) { if(node[j].l>rr||node[j].r<ll) continue; if(node[j].opt==1) { if(node[j].l<=ll&&node[j].r>=rr) updateblock(i,node[j].x); else update(i,max(ll,node[j].l),min(rr,node[j].r),node[j].x); } else { if(node[j].x+tag>500000) continue; if(node[j].l<=ll&&node[j].r>=rr) ans[j]+=siz[node[j].x+tag]; else { int temp=min(rr,node[j].r); for(int k=max(ll,node[j].l);k<=temp;k++) if(val[find(k)]==node[j].x+tag) ans[j]++; } } } } for(int i=1;i<=m;i++) if(node[i].opt==2) printf("%d ",ans[i]); return 0; }