luogu P2801 教主的魔法

背景:

最近学习了分块——优秀的暴力。

题意:

n n 个数,两种操作: M M 操作,将 [ L , R ] [L,R] 的数加上 W W A A 操作,询问 [ L , R ] [L,R] 中不小于 C C 的数的个数。

思路:

显然是主席树 Θ ( n l o g n ) \Theta(nlogn) 的模板题,但是要学以致用。
考虑分块。

分块的本质就是将序列分为 n \sqrt{n} 块,对于每一个整块可以用 Θ ( 1 ) \Theta(1) 来操作(考虑使用 l a z y lazy 等方法)。而对于一个不完整的块,则考虑暴力修改。
容易证明时间复杂度为: Θ ( n ( n + n + n ) ) = Θ ( n n ) \Theta(n*(\sqrt{n}+\sqrt{n}+\sqrt{n}))=\Theta{(n\sqrt{n})}

而这一道题 M M 操作显然可以用 l a z y lazy 来操作;
而对于 A A 操作,则可以考虑用二分,保证每一次的块都是有序的,那么就可以用 Θ ( n l o g n n ) \Theta{(nlogn\sqrt{n})} 的时间出解。
注意:只有在对于一个不完整块操作时才需要排序。

代码:

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
	int n,q,block;
	struct node{int x,id;} a[1000010];
	int u[1000010],belong[1000010],lazy[10010],l[10010],r[10010];
bool cmp(node x,node y)
{
	return x.x>y.x;
}
void work(int x,int y,int z)
{
	if(belong[x]==belong[y])
	{
		for(int i=x;i<=y;i++)
			a[u[i]].x+=z;
		sort(a+l[belong[x]],a+r[belong[x]]+1,cmp);
		for(int i=l[belong[x]];i<=r[belong[x]];i++)
			u[a[i].id]=i;
	}
	else
	{
		for(int i=x;belong[i]==belong[x];i++)
			a[u[i]].x+=z;
		for(int i=y;belong[i]==belong[y];i--)
			a[u[i]].x+=z;
		sort(a+l[belong[x]],a+r[belong[x]]+1,cmp);
		for(int i=l[belong[x]];i<=r[belong[x]];i++)
			u[a[i].id]=i;
		sort(a+l[belong[y]],a+r[belong[y]]+1,cmp);
		for(int i=l[belong[y]];i<=r[belong[y]];i++)
			u[a[i].id]=i;
		for(int i=belong[x]+1;i<=belong[y]-1;i++)
			lazy[i]+=z;
	}
}
int solve(int x,int y,int z)
{
	int ans=0;
	if(belong[x]==belong[y])
	{
		z-=lazy[belong[x]];
		for(int i=x;i<=y;i++)
			if(a[u[i]].x>=z) ans++;
	}
	else
	{
		for(int i=x;belong[i]==belong[x];i++)
			if(a[u[i]].x+lazy[belong[x]]>=z) ans++;
		for(int i=y;belong[i]==belong[y];i--)
			if(a[u[i]].x+lazy[belong[y]]>=z) ans++;
		for(int i=belong[x]+1;i<=belong[y]-1;i++)
		{
			int L=l[i],R=r[i],MID,O=l[i]-1;
			while(L<=R)
			{
				MID=(L+R)>>1;
				if(a[MID].x>=z-lazy[i]) L=MID+1,O=MID; else R=MID-1;
			}
			ans+=O-l[i]+1;
		}
	}
	return ans;
}
int main()
{
	int x,y,z;
	char s[5];
	scanf("%d %d",&n,&q);
	block=sqrt(n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i].x);
		a[i].id=i;
		belong[i]=i/block+1;
		if(belong[i]!=belong[i-1]) l[belong[i]]=i,r[belong[i-1]]=i-1;
	}
	r[belong[n]]=n;
	for(int i=1;i<=belong[n];i++)
		sort(a+l[i],a+r[i]+1,cmp);
	for(int i=1;i<=n;i++)
		u[a[i].id]=i;
	for(int i=1;i<=q;i++)
	{
		scanf("%s %d %d %d",s+1,&x,&y,&z);
		if(x>y) swap(x,y);
		if(s[1]=='M') work(x,y,z); else printf("%d\n",solve(x,y,z));
	}
}

猜你喜欢

转载自blog.csdn.net/zsyz_ZZY/article/details/85195022
今日推荐