A
B

P13978 数列分块入门 3 题解

如果你不了解分块,可以P13977 数列分块入门 2的题解区中找到我(现在找不到了),那里有分块入门的基本介绍

或者是在这儿

这个题跟 P13977 数列分块入门 2 很像。

只是查询操作变成查询前驱罢了。

这非常好查!

这只需要对于每个块排序,然后再块内二分找小于它的最大值。

对于散块直接在原序列暴力查即可。

注意判无解!

注意到数列中存在负数,只需要在二分中和查询中将初始值定为极小值,之后在主函数里特判一下即可!

查询:

inline int Shiroko(int id,int val)
{
	int l = st[id];
	int r = ed[id];
	if(a[l] + laz[id] > val) return -INF;
	if(a[r] + laz[id] < val) return a[r] + laz[id];
	int mid,res = INF; // 
	while(l <= r)
	{
		mid = (l + r) >> 1;
		if(a[mid] + laz[id] < val) l = mid + 1,res = a[mid] + laz[id];
		else r = mid - 1;
	}
	if(res < val) return res;
	return -INF;
}

inline int query(int l,int r,int val)
{
	int res = -INF; //
	for(int i = l;i <= min(ed[id[l]],r);i ++) if(b[i] + laz[id[l]] < val) res = max(res,b[i] + laz[id[l]]);
	if(id[l] != id[r]) for(int i = st[id[r]];i <= r;i ++) if(b[i] + laz[id[r]] < val) res = max(res,b[i] + laz[id[r]]);
	for(int i = id[l] + 1;i <= id[r] - 1;i ++) res = max(res,Shiroko(i,val));
	return res;
}

对于修改也只需要分块正常修改即可(整块上标记,散块暴力改)。

修改:

inline void update(int l,int r,int x)
{
	for(int i = l;i <= min(ed[id[l]],r);i ++) b[i] += x;
	for(int i = st[id[l]];i <= ed[id[l]];i ++) a[i] = b[i];
	sort(a + st[id[l]],a + len + ed[id[l] - 1] + 1);
	if(id[l] != id[r])
	{
		for(int i = st[id[r]];i <= r;i ++) b[i] += x;
		for(int i = st[id[r]];i <= ed[id[r]];i ++) a[i] = b[i];
		sort(a + st[id[r]],a + ed[id[r]] + 1);
	}
	if(id[l] != id[r]) for(int i = id[l] + 1;i <= id[r] - 1;i ++) laz[i] += x;
}

代码:

#include<bits/stdc++.h>
#define int long long
#define con putchar_unlocked(' ')
#define ent putchar_unlocked('\n')
#define Blue_Archive return 0
using namespace std;
const int N = 4e5 + 9;
const int M = 450;
const int INF = 1e18;

int n;
int len;
int top;
int a[N];
int b[N];
int id[N];
int st[M];
int ed[M];
int laz[M];

inline int read()
{
	int k = 0,f = 1;
	char c = getchar_unlocked();
	while(c < '0' || c > '9')
	{
		if(c == '-') f = -1;
		c = getchar_unlocked();
	}
	while(c >= '0' && c <= '9') k = (k << 3) + (k << 1) + c - '0',c = getchar_unlocked();
	return k * f;
}

inline void write(int x)
{
	if(x < 0) putchar_unlocked('-'),x = -x;
	if(x > 9) write(x / 10);
	putchar_unlocked(x % 10 + '0');
}

inline void update(int l,int r,int x)
{
	for(int i = l;i <= min(ed[id[l]],r);i ++) b[i] += x;
	for(int i = st[id[l]];i <= ed[id[l]];i ++) a[i] = b[i];
	sort(a + st[id[l]],a + len + ed[id[l] - 1] + 1);
	if(id[l] != id[r])
	{
		for(int i = st[id[r]];i <= r;i ++) b[i] += x;
		for(int i = st[id[r]];i <= ed[id[r]];i ++) a[i] = b[i];
		sort(a + st[id[r]],a + ed[id[r]] + 1);
	}
	if(id[l] != id[r]) for(int i = id[l] + 1;i <= id[r] - 1;i ++) laz[i] += x;
}

inline int Shiroko(int id,int val)
{
	int l = st[id];
	int r = ed[id];
	if(a[l] + laz[id] > val) return -INF;
	if(a[r] + laz[id] < val) return a[r] + laz[id];
	int mid,res = INF;
	while(l <= r)
	{
		mid = (l + r) >> 1;
		if(a[mid] + laz[id] < val) l = mid + 1,res = a[mid] + laz[id];
		else r = mid - 1;
	}
	if(res < val) return res;
	return -INF;
}

inline int query(int l,int r,int val)
{
	int res = -INF;
	for(int i = l;i <= min(ed[id[l]],r);i ++) if(b[i] + laz[id[l]] < val) res = max(res,b[i] + laz[id[l]]);
	if(id[l] != id[r]) for(int i = st[id[r]];i <= r;i ++) if(b[i] + laz[id[r]] < val) res = max(res,b[i] + laz[id[r]]);
	for(int i = id[l] + 1;i <= id[r] - 1;i ++) res = max(res,Shiroko(i,val));
	return res;
}

signed main()
{
	// freopen("data.in","r",stdin);freopen("data.out","w",stdout);
	n = read();
	len = sqrt(n);
	top = ceil(n * 1.0 / len);
	for(int i = 1;i <= n;i ++)
	{
		b[i] = a[i] = read();
		id[i] = (i - 1) / len + 1;
	}
	for(int i = 1;i <= top;i ++)
	{
		st[i] = (i - 1) * len + 1;
		ed[i] = i * len;
	}
	ed[top] = n;
	for(int i = 1;i <= top;i ++) sort(a + st[i],a + ed[i] + 1);
	for(int i = 1,op,l,r,k,ans;i <= n;i ++)
	{
		op = read();
		l = read();
		r = read();
		k = read();
		if(op == 1)
		{
			ans = query(l,r,k);
		 	write((ans == -INF) ? -1 : ans),ent;
		}
		else update(l,r,k);
	}
	Blue_Archive;
}

感谢阅读,点个赞再走呗~

posted @ 2025-09-07 20:16  MyShiroko  阅读(14)  评论(0)    收藏  举报