【Codeforces 896E】—Welcome home, Chtholly(分块)
这个东西线段树没啥好办法维护
考虑分块
对于每个块每个权值维护一个并查集并且维护一下
考虑一次修改
如果一个整块值域
就把向上合并,再整体打上标记
否则把向下合并
这样可以在的时间内把值域减小
对于散块暴力重构
复杂度
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=100005,M=355;
int n,m,a[N],val[N],fa[N];
int id[M][N],mx[M],mn[M],s[N];
int bel[N],L[M],R[M],blo,cnt;
inline int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void build(int x){
mn[x]=0;int maxn=0;
for(int i=L[x];i<=R[x];i++)fa[i]=i;
for(int i=L[x];i<=R[x];i++){
chemx(maxn,a[i]);
val[i]=a[i];
if(!id[x][val[i]])id[x][val[i]]=i,s[i]=1;
else fa[i]=id[x][val[i]],s[find(i)]++;
}
mx[x]=maxn;
}
inline void rebuild(int x,int l,int r,int k){
for(int i=L[x];i<=R[x];i++)
id[x][val[i]]=0,a[i]=val[find(i)]-mn[x];
for(int i=l;i<=r;i++)if(a[i]>k)a[i]-=k;
build(x);
}
inline void update(int l,int r,int k){
if(bel[l]==bel[r]){
rebuild(bel[l],l,r,k);return;
}
rebuild(bel[l],l,R[bel[l]],k);
rebuild(bel[r],L[bel[r]],r,k);
for(int x=bel[l]+1;x<bel[r];x++){
if(mx[x]-mn[x]>2*k){
for(int i=mn[x]+1;i<=mn[x]+k;i++){
if(!id[x][i])continue;
if(!id[x][i+k])id[x][i+k]=id[x][i],val[id[x][i]]=i+k,id[x][i]=0;
else s[id[x][i+k]]+=s[id[x][i]],fa[id[x][i]]=id[x][i+k],id[x][i]=0;
}
mn[x]+=k;
}
else{
for(int i=mn[x]+k+1;i<=mx[x];i++){
if(!id[x][i])continue;
if(!id[x][i-k])id[x][i-k]=id[x][i],val[id[x][i]]=i-k,id[x][i]=0;
else s[id[x][i-k]]+=s[id[x][i]],fa[id[x][i]]=id[x][i-k],id[x][i]=0;
}
while(!id[x][mx[x]])mx[x]--;
}
}
}
inline int query(int l,int r,int k){
int res=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++)if(val[find(i)]-mn[bel[l]]==k)res++;
return res;
}
for(int i=l;i<=R[bel[l]];i++)
if(val[find(i)]-mn[bel[l]]==k)res++;
for(int i=L[bel[r]];i<=r;i++)
if(val[find(i)]-mn[bel[r]]==k)res++;
for(int i=bel[l]+1;i<bel[r];i++)
if(mn[i]+k<=mx[i])res+=s[id[i][mn[i]+k]];
return res;
}
int main(){
n=read(),m=read();
blo=sqrt(n),cnt=(n-1)/blo+1;
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)bel[i]=(i-1)/blo+1;
for(int i=1;i<=cnt;i++)L[i]=(i-1)*blo+1,R[i]=min(i*blo,n);
for(int i=1;i<=cnt;i++)build(i);
while(m--){
int op=read(),l=read(),r=read(),k=read();
if(op==1){
update(l,r,k);
}
else{
cout<<query(l,r,k)<<'\n';
}
}
}