Ynoi2018 五彩斑斓的世界

Link
维护块内极差/最大值(mx),以及各个数出现的首地址(不一定是第一个),其它的用并查集并过去。
对于修改,分为边角和整块考虑。
边角的话我们把边角所在的块暴力修改并重构,单次复杂度是(O(sqrt n))的。
整块的话我们有两个暴力做法:
一是把(ge x)的数(k)暴力并到(k-x)上去,单次的复杂度是(O(mx-x))
二是给整个块打一个(-x)的标记,然后把(<x)的数(k)暴力并到(k+x)上去,单次的复杂度是(O(x))
我们把这两个暴力拼到一起,如果(mx<2x)就采用第一个暴力,否则采用第二个暴力。
这样可以保证一个块内所有全体修改的总体复杂度不会超过(O(max a))
查询的话直接整块直接查询边角暴力。
注意到题目并没有要求强制在线,所以我们可以把所有操作离线下来,然后一个个块做,这样可以做到(O(n))空间。

#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<utility>
#include<algorithm>
#define fi first
#define se second
namespace IO
{
    char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[11],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
    void Put(char x){*oS++=x;if(oS==oT)Flush();}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
    void write(int x){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('
');}
}using namespace IO;
using pi=std::pair<int,int>;
const int N=500007;
int n,m,B,a[N],b[N],f[N];pi v[N];
struct node{int o,l,r,x,ans;}q[N];
int find(int x){return x==f[x]? x:f[x]=find(f[x]);}
void merge(int x,int y){v[y].fi? f[v[x].fi]=v[y].fi:b[v[y].fi=v[x].fi]=y,v[y].se+=v[x].se,v[x]={0,0};}
#define update()							
    mx=0;								
    for(int k=L,x;k<=R;++k) mx=std::max(mx,x=a[k]),v[x].fi? f[k]=v[x].fi:(b[v[x].fi=f[k]=k]=x),++v[x].se;
int main()
{
    n=read(),m=read();int B=701+(rand()&7);
    for(int i=1;i<=n;++i) a[i]=read();
    for(int i=1;i<=m;++i) q[i]={read(),read(),read(),read()};
    for(int i=1;;++i)
    {
	int L=i*B-B+1,R=std::min(n,i*B),mx,tag=0;
	if(L>n) break;
	memset(v,0,sizeof v),update();
	for(int j=1;j<=m;++j)
	{
	    int l=q[j].l,r=q[j].r,x=q[j].x;
	    if(r<L||R<l) continue;
	    if(q[j].o==1)
	    {
		if(l<=L&&R<=r)
		{
		    if((x<<1)<=mx-tag)
		    {
			for(int k=tag+1;k<=tag+x;++k) if(v[k].fi) merge(k,k+x);
			tag+=x;
		    }
		    else 
		    {
			for(int k=mx;k>tag+x;--k) if(v[k].fi) merge(k,k-x);
			mx=std::min(mx,tag+x);
		    }
		}
		else
		{
		    for(int k=L;k<=R;++k) a[k]=b[find(k)],v[a[k]]={0,0},a[k]-=tag;
		    memset(b+L,0,(R-L+1)<<2),tag=0;l=std::max(l,L),r=std::min(r,R);
		    for(int k=l;k<=r;++k) if(a[k]>x) a[k]-=x;
		    update();
		}
	    }
	    else
	    {
		if(l<=L&&R<=r) { if(x+tag<=500000) q[j].ans+=v[x+tag].se; }
		else { l=std::max(l,L),r=std::min(r,R); for(int k=l;k<=r;++k) if(b[find(k)]==tag+x) ++q[j].ans;}
	    }
	}
    }
    for(int i=1;i<=m;++i) if(q[i].o==2) write(q[i].ans);  
    return Flush(),0;
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12442541.html