感觉有点神秘诶,第一次做操作分块。
和 cdq 要解决的问题挺像的,但处理修改对询问的贡献时无法只与子问题的规模有关,只能把修改变成整块的和散块的,暴力回滚。
算法流程大概是:
对所有操作分块,在每块内:
- 进入该块时保留前面修改的影响
- 按照其它喜欢的方式重新排序
- 如果这是一个询问,暴力把当前块内发生在它之前的修改考虑入内,然后回滚;否则忽略
- 最后保留所有修改,信息可以针对下一个块的询问有一定压缩
需要,如果修改全部在前面且询问全部在后面,均摊足够快速回答每个询问(可以重排询问),且可以回滚。
大概做不了传统的三维偏序,因为处理原有修改的影响不是很好做。 找到分块题解了。
每处理完一个块重构一次答案数组,因为只有下一个块直接使用这个数组,且只有相对大小顺序是重要的,下一个块只有 \(O(\sqrt{n})\) 大小,数组的大小是 \(O(\sqrt{n} \times \sqrt{n}) = O(n)\)。
好像还有一种方法。
每处理完一个块按第二维重排已经扫过的所有三元组,按第二维重排询问,在查询时一边挪指针一边加入前面整块的元素,取块长为 \(B\),复杂度为 \(O(nB \log n + n^2/B \log n) = O(n \sqrt{n} \log n)\) ,不知道能不能过。
#include <bits/stdc++.h>
struct tp {
int u, v, w, i;
tp(int u = 0, int v = 0, int w = 0, int i = 0) : u(u), v(v), w(w), i(i) {}
};
struct opt {
int op, x, y, t;
opt(int op = 0, int x = 0, int y = 0, int t = 0) : op(op), x(x), y(y), t(t) {}
};
const int M = 1e5 + 1;
int fa[M], siz[M];
inline int find(int x) { return fa[x] == x ? x : find(fa[x]); }
int main() {
double st = clock();
int n, m; scanf("%d %d", &n, &m);
std::vector<tp> e(m);
for (int cnt = 0; auto &[u, v, w, i] : e) {
scanf("%d %d %d", &u, &v, &w), --u, --v, i = cnt++;
}
int q; scanf("%d", &q);
int B = 1100;
for (; q; ) {
int s = std::min(q, B);
std::vector<opt> a, c;
std::vector<int> vis(m);
for (int i = 0, op, x, y; i < s; i++) {
scanf("%d %d %d", &op, &x, &y), --x;
if (op == 1) vis[x] = 1, a.emplace_back(op, x, y, i);
else c.emplace_back(op, x, y, i);
}
std::vector<int> b;
for (int i = 0; i < m; i++) if (!vis[i]) b.push_back(i);
std::sort(b.begin(), b.end(), [&](auto x, auto y) -> bool {
return e[x].w > e[y].w;
});
std::sort(c.begin(), c.end(), [&](auto x, auto y) -> bool {
return x.y > y.y;
});
for (int i = 0; i < n; i++)
fa[i] = i, siz[i] = 1;
std::vector<std::pair<int, int>> mdf;
auto merge = [&](int u, int v, bool w) {
if ((u = find(u)) == (v = find(v))) return;
if (siz[u] < siz[v]) std::swap(u, v);
siz[u] += siz[v], fa[v] = u;
if (w) mdf.emplace_back(u, v);
};
int j = 0;
std::vector<int> ans(s, -1);
for (const auto &[op, x, y, t] : c) {
for (; j < (int)b.size() && e[b[j]].w >= y; j++)
merge(e[b[j]].u, e[b[j]].v, 0);
std::vector<std::pair<int, int>> tmp;
for (int k = 0; k < (int)a.size() && a[k].t <= t; k++)
tmp.emplace_back(a[k].x, e[a[k].x].w), e[a[k].x].w = a[k].y;
for (int k = 0; k < (int)a.size(); k++) {
if (e[a[k].x].w >= y)
merge(e[a[k].x].u, e[a[k].x].v, 1);
}
ans[t] = siz[find(x)];
std::reverse(mdf.begin(), mdf.end());
for (const auto &[u, v] : mdf)
siz[u] -= siz[v], fa[v] = v;
mdf.clear();
std::reverse(tmp.begin(), tmp.end());
for (const auto &[x, y] : tmp)
e[x].w = y;
tmp.clear();
}
q -= s;
for (const auto &[op, x, y, t] : a) if (op == 1)
e[x].w = y;
for (auto x : ans) {
if (x != -1) printf("%d\n", x);
}
}
std::cerr << (clock() - st) / CLOCKS_PER_SEC;
}
标签:std,int,siz,vector,auto,P5443,op
From: https://www.cnblogs.com/purplevine/p/18367399