luogu P4117 [Ynoi2018] 五彩斑斓的世界
https://www.luogu.com.cn/problem/P4117
因为题目的值域只有
1
0
5
10^5
105,并且只有减法一种操作,所以我们可以考虑均摊
把所有的减法改成加法
首先还是要分块,维护它的最大值
m
x
mx
mx,如果当前修改
x
x
x
- 2 x > = m x 2x>=mx 2x>=mx,就把所有 > x >x >x的全部减去 x x x
- 否则就把所有 < = x <=x <=x的加上 x x x再把整个块 − x -x −x
那么这个时间复杂度是多少呢?
考虑第一种情况,相当于是用
O
(
m
x
−
x
)
O(mx-x)
O(mx−x)的时间把
m
x
mx
mx变成了最大为
x
x
x的一个数,那么最少减少了
m
x
−
x
mx-x
mx−x
对于第二种情况,相当于是用
O
(
x
)
O(x)
O(x)的时间把最大值mx减少了
x
x
x
那么时间复杂度只和值域有关,即是
O
(
n
)
O(n)
O(n)同阶的
具体写起来就是对于每个块,把每个询问和修改都丢上去,如果完全包含,就整块处理,不然就暴力重构,用并查集维护每个权值即可
有亿点卡常
code:
#include<bits/stdc++.h>
#define N 1000050
#define RE register
using namespace std;
int fa[N], rt[N], size[N], val[N], a[N], n, m, blo, bel[N], mx, tg, ans[N >> 1];
inline int get(int x) { return fa[x] == x? x : fa[x] = get(fa[x]); }
inline void merge(int x, int y) {
if(!rt[y]) {
rt[y] = rt[x];
val[rt[y]] = y;
} else fa[rt[x]] = rt[y];
size[y] += size[x]; rt[x] = size[x] = 0;
}
inline void build(int l, int r) {
memset(rt, 0, sizeof rt);
memset(size, 0, sizeof size);
mx = tg = 0;
for(RE int i = l; i <= r; i ++) { mx = max(mx, a[i]);
if(rt[a[i]]) fa[i] = rt[a[i]];
else {
fa[i] = rt[a[i]] = i;
val[i] = a[i];
}
size[a[i]] ++;
}
}
inline void change(int l, int r, int x) {
if(x * 2 <= mx - tg) {
for(RE int j = tg + 1; j <= tg + x; j ++)
if(rt[j]) merge(j, j + x);
tg += x;
} else {
for(RE int j = mx; j > x + tg; j --)
if(rt[j]) merge(j, j - x);
if(x < mx - tg) mx = tg + x;
}
}
inline void calc(int l, int r, int L, int R, int x, int id) {
if(x + tg > 100001) return ;
// if(id == 2) {
// printf(" %d %d %d\n", l, r, x + tg);
// for(int i = 1; i <= n; i ++) printf("%d ", val[get(i)]); printf("\n");
// }
if(L <= l && r <= R) ans[id] += size[x + tg];
else {
for(RE int i = max(l, L); i <= min(r, R); i ++)
if(val[get(i)] == x + tg) ans[id] ++;
}
}
inline void rebuild(int l, int r, int L, int R, int x) {
for(RE int i = l; i <= r; i ++) a[i] = val[get(i)], size[a[i]] = rt[a[i]] = 0, a[i] -= tg;
for(RE int i = l; i <= r; i ++) val[i] = 0;
for(RE int i = max(l, L); i <= min(r, R); i ++)
if(a[i] > x) a[i] -= x;
mx = tg = 0;
for(RE int i = l; i <= r; i ++) { mx = max(mx, a[i]);
if(rt[a[i]]) fa[i] = rt[a[i]];
else {
fa[i] = rt[a[i]] = i;
val[i] = a[i];
}
size[a[i]] ++;
}
}
struct Q {
int o, l, r, x, id;
} q[N >> 1];
inline int read() {
register int x = 0;
register char ch = getchar();
for(; ch < '0' || ch > '9'; ) ch = getchar();
for(; ch >= '0' && ch <= '9'; ) x = (x << 3) + (x << 1) + (ch - 48), ch = getchar();
return x;
}
inline void write(register int x) {
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
int main() {
n = read(), m = read();
for(RE int i = 1; i <= n; i ++) a[i] = read();
blo = 1200;
// blo = min(n, 2 * m / (int)sqrt(n) + 1);
for(RE int i = 1; i <= n; i ++) bel[i] = (i - 1) / blo + 1;
// printf("** %d\n", blo);
int tot = 0;
for(RE int i = 1; i <= m; i ++) q[i].o = read(), q[i].l = read(), q[i].r = read(), q[i].x = read(), q[i].id = q[i].o == 2? ++ tot : 0;
for(RE int i = 1; i <= bel[n]; i ++) {
int l = (i - 1) * blo + 1, r = min(n, i * blo);
build(l, r);
for(RE int j = 1; j <= m; j ++) {
int L = q[j].l, R = q[j].r, x = q[j].x, o = q[j].o, id = q[j].id;
if(R < l || L > r) continue;
if(o == 1) {
if(L <= l && r <= R) change(l, r, x);
else rebuild(l, r, L, R, x);
// printf(" %d %d %d %d %d %d\n", l, r, L, R, x, ans[2]);
} else calc(l, r, L, R, x, id);
}
}
for(RE int i = 1; i <= tot; i ++) write(ans[i]), puts("");
return 0;
}
/*
10 5
3 4 6 6 4 4 9 9 7 6
2 5 9 3
1 1 3 3
1 6 10 2
1 10 10 8
2 4 10 6
*/