人人本着希望之名

望月悲叹的最初分块

严格强于区间 rank, 直接考虑分块.

平凡的 O(nnlogn) 做法缺点在于二分这个东西完全用不到分块容易预处理的优秀性质. 本题的值域很小, 二分直接扔掉.

相比较而言, 值域分块和序列分块契合度更高, 考虑值域分块.

gi,j 表示前 i 块有 gi,j 个数值为 j, Gi,j 表示前 i 块有 Gi,j 个数值域在第 j 块.

查询时先把散块的信息算出来, 然后在值域块上跳, 单次查询块内信息是 O(1) 的, 整体复杂度 O((n+m)n).

然后考虑修改. 发现这个修改严格弱于 loj516, 散块暴力重构, 整块打 tag. 整体的复杂度还是 O((n+m)n). 代码还没有, 别急. 有代码了.

#include <bits/stdc++.h>
#define pb emplace_back
#define fir first
#define sec second
using i64 = long long;
using pii = std::pair<int, int>;
const int maxn = 1e5 + 5;
const int T = 330;
int n, m, S, V, mx, a[maxn], t, vt, L[T], R[T], pos[maxn], vL[T], vR[T];
int vpos[maxn], val[maxn], pre[maxn], rec[T][maxn], g[T][maxn], G[T][maxn];
struct Query {
int op, l, r, x, y;
Query() {
op = l = r = x = y = 0;
}
Query(int op, int l, int r, int x = 0, int y = 0) : op(op), l(l), r(r), x(x), y(y) {}
} Q[maxn];
int read() {
int s = 0;
char c = getchar();
for(;c < '0'||c > '9';c = getchar());
for(;c >= '0'&&c <= '9';c = getchar())
s = (s << 1) + (s << 3) + (c ^ '0');
return s;
}
void write(int x) {
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
return ;
}
int find(int x) {
return x == pre[x] ? x : pre[x] = find(pre[x]);
}
void merge(int blo, int x, int y) {
if(!rec[blo][x])
return ;
if(!rec[blo][y])
val[rec[blo][y] = rec[blo][x]] = y;
else
pre[rec[blo][x]] = pre[rec[blo][y]];
return rec[blo][x] = 0, void();
}
void rebuild(int blo, int l, int r, int x, int y) {
for(int i = L[blo];i <= R[blo];++ i)
a[i] = val[find(i)], rec[blo][a[i]] = 0;
for(int i = l;i <= r;++ i)
if(a[i] == x)
a[i] = y;
for(int i = L[blo];i <= R[blo];++ i) {
if(!rec[blo][a[i]])
rec[blo][a[i]] = pre[i] = i, val[i] = a[i];
else
pre[i] = rec[blo][a[i]];
}
return ;
}
void modify(int l, int r, int x, int y) {
if(x == y)
return ;
const int p = pos[l], q = pos[r], vpx = vpos[x], vpy = vpos[y];
int sum = 0, tmp = 0;
if(p == q) {
for(int i = l;i <= r;++ i)
sum += val[find(i)] == x;
if(!sum)
return ;
for(int i = p;i <= t;++ i)
g[i][x] -= sum, G[i][vpx] -= sum, g[i][y] += sum, G[i][vpy] += sum;
return rebuild(p, l, r, x, y);
}
for(int i = l;i <= R[p];++ i)
sum += val[find(i)] == x;
if(sum)
rebuild(p, l, R[p], x, y);
for(int i = p;i < q;++ i)
sum += tmp, G[i][vpx] -= sum, G[i][vpy] += sum, tmp = g[i + 1][x] - g[i][x], g[i][x] -= sum, g[i][y] += sum;
tmp = 0;
for(int i = L[q];i <= r;++ i)
if(val[find(i)] == x)
++ sum, ++ tmp;
for(int i = q;i <= t;++ i)
G[i][vpx] -= sum, G[i][vpy] += sum, g[i][x] -= sum, g[i][y] += sum;
for(int i = p + 1;i < q;++ i)
merge(i, x, y);
if(tmp)
rebuild(q, L[q], r, x, y);
return ;
}
int buc[maxn], vbuc[maxn];
int query(int l, int r, int k) {
const int p = pos[l], q = pos[r];
if(k > r - l + 1)
return -1;
if(p == q) {
for(int i = l, x;i <= r;++ i)
++ buc[x = val[find(i)]], ++ vbuc[vpos[x]];
for(int blo = 1;blo <= vt;++ blo) {
if(k > vbuc[blo])
k -= vbuc[blo];
else
for(int z = vL[blo];z <= vR[blo];++ z) {
if(k > buc[z])
k -= buc[z];
else {
for(int i = l, x;i <= r;++ i)
-- buc[x = val[find(i)]], -- vbuc[vpos[x]];
return z;
}
}
}
return 0;
}
for(int i = l, x;i <= R[p];++ i)
++ buc[x = val[find(i)]], ++ vbuc[vpos[x]];
for(int i = L[q], x;i <= r;++ i)
++ buc[x = val[find(i)]], ++ vbuc[vpos[x]];
for(int blo = 1;blo <= vt;++ blo) {
if(k > G[q - 1][blo] - G[p][blo] + vbuc[blo])
k -= G[q - 1][blo] - G[p][blo] + vbuc[blo];
else
for(int z = vL[blo];z <= vR[blo];++ z) {
if(k > g[q - 1][z] - g[p][z] + buc[z])
k -= g[q - 1][z] - g[p][z] + buc[z];
else {
for(int i = l, x;i <= R[p];++ i)
-- buc[x = val[find(i)]], -- vbuc[vpos[x]];
for(int i = L[q], x;i <= r;++ i)
-- buc[x = val[find(i)]], -- vbuc[vpos[x]];
return z;
}
}
}
return 0;
}
int main() {
n = read(), m = read();
S = std::sqrt(n);
t = (n - 1) / S + 1;
for(int i = 1;i <= t;++ i)
L[i] = R[i - 1] + 1, R[i] = R[i - 1] + S;
R[t] = n;
for(int i = 1;i <= t;++ i)
for(int j = L[i];j <= R[i];++ j) {
V = std::max(V, a[j] = read());
if(!rec[i][a[j]])
pre[j] = rec[i][a[j]] = j, val[j] = a[j];
else
pre[j] = rec[i][a[j]];
pos[j] = i;
}
for(int i = 1;i <= m;++ i) {
Q[i].op = read();
Q[i].l = read();
Q[i].r = read();
Q[i].x = read();
if(Q[i].op == 1)
Q[i].y = read(), V = std::max(V, Q[i].x), V = std::max(V, Q[i].y);
}
mx = V;
V = std::sqrt(V);
vt = (mx - 1) / V + 1;
for(int i = 1;i <= vt;++ i)
vL[i] = vR[i - 1] + 1, vR[i] = vR[i - 1] + V;
vR[vt] = mx;
for(int i = 1;i <= vt;++ i)
for(int j = vL[i];j <= vR[i];++ j)
vpos[j] = i;
for(int i = 1;i <= t;++ i) {
for(int j = L[i];j <= R[i];++ j)
++ g[i][a[j]], ++ G[i][vpos[a[j]]];
for(int j = 1;j <= mx;++ j) {
g[i][j] += g[i - 1][j];
if(j <= vt)
G[i][j] += G[i - 1][j];
}
}
for(int i = 1;i <= m;++ i)
if(Q[i].op == 1)
modify(Q[i].l, Q[i].r, Q[i].x, Q[i].y);
else
write(query(Q[i].l, Q[i].r, Q[i].x)), putchar('\n');
return 0;
}
posted @   ImALAS  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示