auto build = [&](auto F, int p, int l, int r) -> void { if (l == r) { T[p].set(a[l], l); return; } int mid = l + ((r - l) >> 1); F(F, 2 * p, l, mid), F(F, 2 * p + 1, mid + 1, r); T[p] = up(T[p * 2], T[p * 2 + 1]); }; build(build, 1, 1, n);
auto query = [&](auto F, int p, int l, int r, int ql, int qr, bool debug = false) -> Node { if (qr < ql) returnNode(); // empty range
if (ql <= l && r <= qr) return T[p]; int mid = l + ((r - l) >> 1); Node res; if (qr <= mid) res = F(F, 2 * p, l, mid, ql, qr, debug); elseif (ql > mid) res = F(F, 2 * p + 1, mid + 1, r, ql, qr, debug); else { Node left = F(F, 2 * p, l, mid, ql, mid, debug); Node right = F(F, 2 * p + 1, mid + 1, r, mid + 1, qr, debug); res = up(left, right); } return res; };
auto q1 = [&](int L) { if (L == 1) returntrue; else { Node t = query(query, 1, 1, n, 1, L - 1); return t.max_ssum < 0/* max suffix sum of [1, l-1] < 0 */; } }; auto q2 = [&](int R) { if (R == n) returntrue; else { Node t = query(query, 1, 1, n, R + 1, n); return t.max_psum < 0/* max prefix sum of [r+1, n] < 0 */; } };
Node maxx = query(query, 1, 1, n, 1, n); // std::cerr << "global max subarray sum=" << maxx.max_inseg_sum << "\n";
while (q--) { int ql, qr; std::cin >> ql >> qr; bool b1 = q1(ql), b2 = q2(qr); if (!b1 || !b2) { std::cout << "-1\n"; continue; }
Node t = query(query, 1, 1, n, ql, qr); auto mid = query(query, 1, 1, n, ql + 1, qr - 1); Node lf = query(query, 1, 1, n, 1, ql - 1); Node rf = query(query, 1, 1, n, qr + 1, n); ll outside = std::max({lf.max_inseg_sum, rf.max_inseg_sum, 0ll});
#include<algorithm> #include<iostream> #include<map> #include<queue> #include<utility> #include<vector> using vi = std::vector<int>; constexprint N = 2e5 + 5;
structedge { int uv, c, tc; int colored; } E[N];
vi G[N]; std::map<int, int> C[N]; int vis[N];
intmain(){ int n, m, k; std::cin >> n >> m >> k; for (int i = 0, u, v, c, t; i < m; i++) { std::cin >> u >> v >> c >> t; E[i] = {u ^ v, c, t, false}; G[u].push_back(i), G[v].push_back(i); C[u][t]++, C[v][t]++; }
std::queue<int> q; std::vector<std::pair<int, int>> ans; for (int i = 1; i <= n; i++) if (C[i].size() == 1) q.push(i), vis[i] = true;
int cnt = 0; while (!q.empty()) { int u = q.front(); ans.push_back({u, C[u].begin()->first}); for (auto eid : G[u]) E[eid].colored = true; cnt++; q.pop();
for (int eid : G[u]) { int v = E[eid].uv ^ u; if (vis[v]) continue;
C[v][E[eid].tc]--; if (C[v][E[eid].tc] == 0) C[v].erase(E[eid].tc);
for (int b = 1; b <= blocks; b++) { for (int c = std::max(1, (min[b] + m - 1) / m); c * m <= max[b]; c++) { if (c * m < block_add[b]) continue; i64 cnt = cntpoint[b][c * m - block_add[b]]; ans[c] += cnt * len; } }
prvX = x; i = j; }
所以,一个代码难度更小的做法是,直接让 x 从 1 到 n 递增,且只处理横座标为 x 的线段,在分块上维护。维护完后统计点数。这样,查询的时间复杂度是 O(mn2),也不会 TLE.
#include<algorithm> #include<cassert> #include<cmath> #include<iostream> #include<vector> constexprint N = 3e5 + 5; constexprint B = 600; using i64 = longlong;
structRec { int l, r, t, b; } r[N]; structSeg { int x, ub, lb, exit, id; }; int n, m; std::vector<Seg> scan[N];
int blocksize, blocks; int bid[N], bl[B], br[B]; int cnty[N], prvX{-1}, block_add[B], max[B], min[B]; int cntpoint[B][N]; i64 ans[B];
voidrebuild(int l, int r, int w){ assert(bid[l] == bid[r]); int id = bid[l];
for (int i = bl[id]; i <= br[id]; i++) cntpoint[id][cnty[i]]--; max[id] = 0, min[id] = N; for (int i = bl[id]; i <= br[id]; i++) { cnty[i] += block_add[id]; if (l <= i && i <= r) cnty[i] += w; cntpoint[id][cnty[i]]++; max[id] = std::max(max[id], cnty[i]); min[id] = std::min(min[id], cnty[i]); } block_add[id] = 0; }
voidadd(int l, int r, int w){ if (bid[l] == bid[r]) rebuild(l, r, w); else { rebuild(l, br[bid[l]], w); for (int i = bid[l] + 1; i <= bid[r] - 1; i++) block_add[i] += w, max[i] += w, min[i] += w; rebuild(bl[bid[r]], r, w); } }
voiddebug(){ for (int b = 1; b <= blocks; b++) { std::cerr << "Block " << b << ": \n"; for (int i = bl[b]; i <= br[b]; i++) std::cerr << "\tPos " << i << " = " << cnty[i] + block_add[b] << "\n"; for (int cnt = 0; cnt <= max[b]; cnt++) { if (cntpoint[b][cnt] == 0) continue; std::cerr << "\tCount " << cnt + block_add[b] << ": " << cntpoint[b][cnt] << " points\n"; } } }
intmain(){ std::cin.tie(0)->sync_with_stdio(0); std::cin >> n >> m; for (int i = 1; i <= n; i++) { std::cin >> r[i].l >> r[i].r >> r[i].b >> r[i].t; r[i].t--; scan[r[i].l].push_back({r[i].l, r[i].t, r[i].b, 1, i}); // scan.push_back({r[i].r - 1, r[i].t, r[i].b, 0, i}); scan[r[i].r].push_back({r[i].r, r[i].t, r[i].b, -1, i}); }
// blocks blocksize = (int)std::sqrt(n); for (int i = 1; i <= n; i++) bid[i] = (i - 1) / blocksize + 1; for (int i = 1; i <= bid[n]; i++) { bl[i] = (i - 1) * blocksize + 1; br[i] = i * blocksize; } br[bid[n]] = n, blocks = bid[n]; for (int b = 1; b <= blocks; b++) { cntpoint[b][0] = br[b] - bl[b] + 1; max[b] = 0, min[b] = 0; }
for (int i = 1; i <= n; i++) { for (auto [x, ub, lb, v, id] : scan[i]) add(lb, ub, v);
for (int b = 1; b <= blocks; b++) { for (int c = std::max(1, (min[b] + m - 1) / m); c * m <= std::min(n, max[b]); c++) { if (c * m < block_add[b]) continue; ans[c] += (i64)cntpoint[b][c * m - block_add[b]]; } } }
for (int c = 1; c * m <= n; c++) std::cout << ans[c] << "\n"; }