P2801 教主的魔法(分块算法)

105 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

传送门

题意:

给你n个人,每次可以选择两种操作:1、让一段区间中的人身高增长w。2、查询一段区间中身高高于c的人数。

思路:

使用分块算法,用数组b来表示散块每次进行更改后的值,并对其进行排序,查询时查询b数组即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9+7;
#define mem(a,b) memset(a,0,sizeof(a));
ll st[1000100],ed[1000100],a[1000100],b[10000100];
ll sum[1000100],add[1000100],pos[1000100];
void change(ll l,ll r,ll w)
{
	ll p = pos[l],q = pos[r];
	if(p == q)
	{
		for(ll i = l; i <= r; i++)
		{
			a[i] += w;
		}
		for(ll i = l; i <= r; i++)
		b[i] = a[i];
		sort(b+l,b+r+1);
	}
	else
	{
		for(ll i = p+1; i <= q-1; i++)add[i]+=w;
        for(ll i = l; i <= ed[p]; i++)a[i]+=w;
        for(ll i = st[p]; i <= ed[p]; i++)b[i] = a[i];
        sort(b+st[p],b+ed[p]+1);
    	for(ll i = st[q]; i <= r; i++)a[i]+=w;
    	for(ll i = st[q]; i <= ed[q]; i++)b[i] = a[i];
		sort(b+st[q],b+ed[q]+1); 
	}
}
ll ask(ll l,ll r,ll w)
{
	ll ans = 0;
	ll p = pos[l],q = pos[r];
	if(p == q)
	{
		ans = lower_bound(b+l,b+r,w-add[p])-b;
		if(w-add[p] <= b[ans])ans = r-ans+1;
		else ans = r-ans;
		
	}
	else
	{
		ll num = 0;
		for(ll i = p+1; i <= q-1; i++)
		{
			num = lower_bound(b+st[i],b+ed[i],w-add[i])-b;
			ans += ed[i]-num;
			if(w-add[i] <= b[num])ans++;
		}
		num = lower_bound(b+l,b+ed[p],w-add[p])-b;
		ans += ed[p]-num;
		if(w-add[p] <= b[num])ans++;
		num = lower_bound(b+st[q],b+r,w-add[q])-b;
		ans += ed[q]-num;
		if(w-add[p] <= b[num])ans++;
	}
	return ans;
}
int main()
{
	ll n,q;
	cin>>n>>q;
	ll len = sqrt(n);
	for(ll i = 1; i <= n; i++)
	{
		cin>>a[i];
		pos[i] = (i-1)/len+1;
		sum[(i-1)/len+1]+=a[i];
		b[i] = a[i];
	}
	ll maxx = n%len?n/len+1:n/len;
	for(ll i = 1; i <= maxx; i++)
	st[i] = (i-1)*len+1,ed[i] = i==maxx?n:i*len;
	for(ll i = 1; i <= maxx; i++)
	sort(b+st[i], b+ed[i]+1);
	while(q--)
	{
		char op;
		scanf(" %c",&op);
		if(op == 'M')
		{
			ll l,r,w;
			cin>>l>>r>>w;
			change(l,r,w);
		}
		else
		{
			ll l,r,w;
			cin>>l>>r>>w;
			cout<<ask(l,r,w)<<endl;
		}
	}
}