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;
}
感谢阅读,点个赞再走呗~
与你的日常,便是奇迹

浙公网安备 33010602011771号