【Codeforces 896E】—Welcome home, Chtholly(分块)

传送门

这个东西线段树没啥好办法维护
考虑分块
对于每个块每个权值维护一个并查集并且维护一下sizsiz
考虑一次修改
如果一个整块值域>2x>2x
就把[1,x][1,x]向上合并,再整体打上标记
否则把[x+1,mx][x+1,mx]向下合并
这样可以在O(x)O(x)的时间内把值域减小xx
对于散块暴力重构
复杂度O(nn+mn)O(n\sqrt n+m\sqrt n)

#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';
		}
	}
}
posted @ 2019-09-10 21:16  Stargazer_cykoi  阅读(96)  评论(0编辑  收藏  举报