【Ynoi2018】五彩斑斓的世界

【Ynoi2018】五彩斑斓的世界

by AmanoKumiko

Description

给出一个长度为n的序列am次操作

每次操作形如

1,l,r,x 给区间中大于x的数减去x

2,l,r,x 询问区间中x的出现次数

Input

第一行两个数n,m

第二行n个数读入序列

然后m行读入操作

Output

每组询问输出一个数表示答案

Sample Input

5 6
1 5 5 5 8
2 2 5 5
1 2 4 3
2 2 5 2
2 2 5 5
1 3 5 1
2 1 5 1

Sample Output

3
3
0
3

Data Constraint

1n106,1m5105,0a,x105

Solution

我们先思考两个朴素的做法

令最大值为m

1.暴力扫[x+1,m]中的数,减去x

x=1时显然复杂度是错的

2.暴力扫[1,x]中的数,加上x,然后区间减去x

x=105时复杂度是错的

仔细分析,我们的值是单调不降的,

那么只要我们每次都能用一定的时间换取极差减少相应的值,

每个块的复杂度就达到了O(105)

换句话说,我们要平衡上面的两种做法

可以发现

mxx时,第一种做法复杂度O(mx),极差减少了O(mx)

mx>x时,第二种做法复杂度O(x),极差减少了O(x)

那么用并查集(第一分块)维护下出现次数就行了

这里还有个问题,空间只有64MB

我们采取一个nb的trick:逐块处理,这样就解决啦

Code

#include<bits/stdc++.h>
using namespace std;
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define N 1000010
#define M 500010

namespace IO{
	const int sz=1<<22;
	char a[sz+5],b[sz+5],*p1=a,*p2=a,*t=b,p[105];
	inline char gc(){
		return p1==p2?(p2=(p1=a)+fread(a,1,sz,stdin),p1==p2?EOF:*p1++):*p1++;
	}
	template<class T>void read(T&x){
		x=0;char c=gc();
		for(;c<'0'||c>'9';c=gc());
		for(;c>='0'&&c<='9';c=gc())x=x*10+(c-'0');
	}
	inline void flush(){fwrite(b,1,t-b,stdout),t=b;}
	inline void pc(char x){*t++=x;if(t-b==sz)flush();}
	template<class T>void write(T x,char c='\n'){
		if(x==0)pc('0');int t=0;
		for(;x;x/=10)p[++t]=x%10+'0';
		for(;t;--t)pc(p[t]);pc(c);
	}
	struct F{~F(){flush();}}f;
}
using IO::read;
using IO::write;

int n,m,a[N],val[N],ans[N],be[N],L[N],R[N],wh[N],fa[N],cnt[N],Mx,tag;
struct node{int op,l,r,x;}q[M];

inline int get(int x){return fa[x]==x?x:(fa[x]=get(fa[x]));}

inline void rebuild(int x){
	Mx=tag=0;
	fd(i,R[x],L[x])wh[a[i]]=i,cnt[a[i]]=0,val[i]=0;
	fo(i,L[x],R[x]){
		Mx=max(Mx,a[i]);
		cnt[a[i]]++;
		fa[i]=wh[a[i]];
		if(fa[i]==i)val[i]=a[i];
	}
}

inline void clear(int x){
	fo(i,L[x],R[x])wh[val[get(i)]]=cnt[val[get(i)]]=0,a[i]=val[get(i)]-tag;
	fo(i,L[x],R[x])wh[a[i]]=cnt[a[i]]=0;
}

inline void line(int x,int y){
	if(wh[y]){
		cnt[y]+=cnt[x];
		cnt[x]=0;
		fa[wh[x]]=wh[y];
		wh[x]=0;
	}else{
		cnt[y]=cnt[x];
		cnt[x]=0;
		val[wh[y]=wh[x]]=y;
		wh[x]=0;
	}
}

int main(){
	read(n);read(m);
	fo(i,1,n)read(a[i]);
	fo(i,1,m)read(q[i].op),read(q[i].l),read(q[i].r),read(q[i].x);
	int sz=1300,cs=n/sz+1;
	fo(i,1,cs){
		L[i]=R[i-1]+1;R[i]=min(L[i]+sz-1,n);
		fo(j,L[i],R[i])be[j]=i;
	}
	fo(i,1,cs){
		rebuild(i);
		fo(j,1,m){
			int le=q[j].l,ri=q[j].r;
			le=max(le,L[i]);ri=min(ri,R[i]);
			if(le<=ri){
				if(q[j].op==1){
					if(Mx-tag<=q[j].x)continue;
					if(le==L[i]&&ri==R[i]){
						if(Mx-tag<=q[j].x*2){
							fo(k,q[j].x+tag+1,Mx)if(wh[k])line(k,k-q[j].x);
							Mx=min(Mx,q[j].x+tag);
						}else{
							fo(k,tag+1,tag+q[j].x)if(wh[k])line(k,k+q[j].x);
							tag+=q[j].x;
						}
					}else{
						fo(k,L[i],R[i])wh[val[get(k)]]=cnt[val[get(k)]]=0,a[k]=val[get(k)]-tag;
						fo(k,le,ri)if(a[k]>q[j].x)a[k]-=q[j].x;
						rebuild(i);
					}
				}else{
					if(le==L[i]&&ri==R[i]){
						if(wh[q[j].x+tag])ans[j]+=cnt[q[j].x+tag];
					}else{
						fo(k,le,ri)if(val[get(k)]==q[j].x+tag)ans[j]++;
					}
				}
			}
		}
		clear(i);
	}
	fo(i,1,m)if(q[i].op==2)write(ans[i]);
	return 0;
}
posted @   冰雾  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示