Solution
單次二分:問“重要度 \(\ge x\) 的所有操作,且 \(t\) 時間點還存在的所有操作中,是否有不經過這個點的”
整體二分:保持操作、詢問按時間有序,即預先按時間排序,下傳時保持有序;
對於一次 Solve,對於所有重要度 \(\ge mid+1\) 的操作(加入、刪除),考慮與詢問按時間混合排序,然後依次回答。
這裡有比樹剖更好的處理方法:樹上差分,一次加入路徑 \((u,v)\) 就給 \(u,v\) 加一,\(lca,fa(lca)\) 減一;一次詢問 \(u\) 就查 \(u\) 子樹和是否等於運算元,樹狀陣列可以實現。
用不用 \(O(1)\) LCA 都是 \(O(n\log^2 n)\) 的.
Code 1
\(\text{vector}\) 版整體二分,未卡常
#include <bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for (int i = (j); i <= (k); ++i)
#define reo(i, j, k) for (int i = (j); i >= (k); --i)
typedef long long ll;
const int N = 1e5 + 10, M = 2e5 + 10;
int n, m, tot, ans[N];
vector<int> G[N];
struct Item {
int op, u, v, w, tim, id;
};
int tim, dfn[N], dep[N], sz[N], son[N], Top[N], Fa[N];
void DFS1(int u, int fa) {
sz[u] = 1, Fa[u] = fa, dep[u] = dep[fa] + 1;
for (int v : G[u])
if (v != fa) {
DFS1(v, u), sz[u] += sz[v];
if (sz[v] > sz[son[u]]) son[u] = v;
}
}
void DFS2(int u, int tp) {
dfn[u] = ++tim, Top[u] = tp;
if (son[u]) DFS2(son[u], tp);
for (int v : G[u])
if (v != Fa[u] && v != son[u])
DFS2(v, v);
}
int LCA(int u, int v) {
while (Top[u] != Top[v]) {
if (dep[Top[u]] < dep[Top[v]]) swap(u, v);
u = Fa[Top[u]];
}
return dep[u] < dep[v] ? u : v;
}
struct BIT {
ll sum[N];
BIT() {
memset(sum, 0, sizeof(sum));
}
void Upd(int x, ll v) {
for (; x <= n; x += x & -x) sum[x] += v;
}
ll Qry(int x) {
ll res = 0;
for (; x; x -= x & -x) res += sum[x];
return res;
}
ll Qry(int x, int y) {
return Qry(y) - Qry(x - 1);
}
} bit;
void Solve(int l, int r, vector<Item> &Op) {
int cntQ = 0;
for (auto it : Op) cntQ += it.op == 2;
if (!cntQ) return;
if (l == r) {
for (auto it : Op) {
if (it.op == 2) ans[it.id] = (l == 1) ? -1 : (l - 1);
}
return;
}
int mid = (l + r) >> 1;
vector<Item> OpL, OpR;
int cnt = 0;
for (auto it : Op) {
if (it.op == 0) {
if (it.w >= mid) {
int u = it.u, v = it.v, lca = LCA(u, v), fa = Fa[lca];
bit.Upd(dfn[u], 1), bit.Upd(dfn[v], 1), bit.Upd(dfn[lca], -1);
if (fa) bit.Upd(dfn[fa], -1);
++cnt;
}
if (it.w > mid) OpR.push_back(it);
else OpL.push_back(it);
}
if (it.op == 1) {
if (it.w >= mid) {
int u = it.u, v = it.v, lca = LCA(u, v), fa = Fa[lca];
bit.Upd(dfn[u], -1), bit.Upd(dfn[v], -1), bit.Upd(dfn[lca], 1);
if (fa) bit.Upd(dfn[fa], 1);
--cnt;
}
if (it.w > mid) OpR.push_back(it);
else OpL.push_back(it);
}
if (it.op == 2) {
int res = bit.Qry(dfn[it.u], dfn[it.u] + sz[it.u] - 1);
if (res == cnt) {
OpL.push_back(it);
} else {
OpR.push_back(it);
}
}
}
for (auto it : Op) {
if (it.op == 0 && it.w >= mid) {
int u = it.u, v = it.v, lca = LCA(u, v), fa = Fa[lca];
bit.Upd(dfn[u], -1), bit.Upd(dfn[v], -1), bit.Upd(dfn[lca], 1);
if (fa) bit.Upd(dfn[fa], 1);
}
if (it.op == 1 && it.w >= mid) {
int u = it.u, v = it.v, lca = LCA(u, v), fa = Fa[lca];
bit.Upd(dfn[u], 1), bit.Upd(dfn[v], 1), bit.Upd(dfn[lca], -1);
if (fa) bit.Upd(dfn[fa], -1);
}
}
Solve(l, mid, OpL), Solve(mid + 1, r, OpR);
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
cin >> n >> m;
rep(i, 1, n - 1) {
int u, v;
cin >> u >> v, G[u].push_back(v), G[v].push_back(u);
}
int mx = 0;
vector<Item> Op(m);
rep(i, 0, m - 1) {
int x;
cin >> Op[i].op;
if (Op[i].op == 0)
cin >> Op[i].u >> Op[i].v >> Op[i].w, mx = max(mx, Op[i].w);
if (Op[i].op == 1)
cin >> x, --x, Op[i].u = Op[x].u, Op[i].v = Op[x].v, Op[i].w = Op[x].w;
if (Op[i].op == 2)
cin >> Op[i].u, Op[i].id = ++tot;
}
DFS1(1, 0), DFS2(1, 1);
Solve(1, mx + 1, Op);
rep(i, 1, tot)
cout << ans[i] << '\n';
return 0;
}
Code 2
普通整體二分
#include <bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for (int i = (j); i <= (k); ++i)
#define reo(i, j, k) for (int i = (j); i >= (k); --i)
typedef long long ll;
const int N = 1e5 + 10, M = 2e5 + 10;
int n, m, tot, ans[M];
vector<int> G[N];
struct Item {
int op, u, v, w, tim, id;
} Op[M];
int id[M], _id[M], vis[M];
int tim, dfn[N], dep[N], sz[N], son[N], Top[N], Fa[N];
void DFS1(int u, int fa) {
sz[u] = 1, Fa[u] = fa, dep[u] = dep[fa] + 1;
for (int v : G[u])
if (v != fa) {
DFS1(v, u), sz[u] += sz[v];
if (sz[v] > sz[son[u]]) son[u] = v;
}
}
void DFS2(int u, int tp) {
dfn[u] = ++tim, Top[u] = tp;
if (son[u]) DFS2(son[u], tp);
for (int v : G[u])
if (v != Fa[u] && v != son[u])
DFS2(v, v);
}
int LCA(int u, int v) {
while (Top[u] != Top[v]) {
if (dep[Top[u]] < dep[Top[v]]) swap(u, v);
u = Fa[Top[u]];
}
return dep[u] < dep[v] ? u : v;
}
struct BIT {
ll sum[N];
BIT() {
memset(sum, 0, sizeof(sum));
}
void Upd(int x, ll v) {
for (; x <= n; x += x & -x) sum[x] += v;
}
ll Qry(int x) {
ll res = 0;
for (; x; x -= x & -x) res += sum[x];
return res;
}
ll Qry(int x, int y) {
return Qry(y) - Qry(x - 1);
}
} bit;
void Solve(int l, int r, int ql, int qr) {
int cntQ = 0;
rep(i, ql, qr) cntQ += Op[id[i]].op == 2;
if (!cntQ) return;
if (l == r) {
rep(i, ql, qr) {
auto it = Op[id[i]];
if (it.op == 2) ans[it.id] = (l == 1) ? -1 : (l - 1);
}
return;
}
int mid = (l + r) >> 1, cnt = 0, L = ql - 1, R;
rep(i, ql, qr) {
auto it = Op[id[i]];
if (it.op == 0) {
if (it.w >= mid) {
int u = it.u, v = it.v, lca = LCA(u, v), fa = Fa[lca];
bit.Upd(dfn[u], 1), bit.Upd(dfn[v], 1), bit.Upd(dfn[lca], -1);
if (fa) bit.Upd(dfn[fa], -1);
++cnt;
}
if (it.w > mid) vis[i] = 1;
else _id[++L] = id[i], vis[i] = 0;
}
if (it.op == 1) {
if (it.w >= mid) {
int u = it.u, v = it.v, lca = LCA(u, v), fa = Fa[lca];
bit.Upd(dfn[u], -1), bit.Upd(dfn[v], -1), bit.Upd(dfn[lca], 1);
if (fa) bit.Upd(dfn[fa], 1);
--cnt;
}
if (it.w > mid) vis[i] = 1;
else _id[++L] = id[i], vis[i] = 0;
}
if (it.op == 2) {
int res = bit.Qry(dfn[it.u], dfn[it.u] + sz[it.u] - 1);
if (res == cnt) {
_id[++L] = id[i], vis[i] = 0;
} else {
vis[i] = 1;
}
}
}
R = L;
rep(i, ql, qr)
if (vis[i]) _id[++R] = id[i];
rep(i, ql, qr) {
auto it = Op[id[i]];
if (it.op == 0 && it.w >= mid) {
int u = it.u, v = it.v, lca = LCA(u, v), fa = Fa[lca];
bit.Upd(dfn[u], -1), bit.Upd(dfn[v], -1), bit.Upd(dfn[lca], 1);
if (fa) bit.Upd(dfn[fa], 1);
}
if (it.op == 1 && it.w >= mid) {
int u = it.u, v = it.v, lca = LCA(u, v), fa = Fa[lca];
bit.Upd(dfn[u], 1), bit.Upd(dfn[v], 1), bit.Upd(dfn[lca], -1);
if (fa) bit.Upd(dfn[fa], -1);
}
}
rep(i, ql, qr) id[i] = _id[i];
Solve(l, mid, ql, L), Solve(mid + 1, r, L + 1, qr);
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
cin >> n >> m;
rep(i, 1, n - 1) {
int u, v;
cin >> u >> v, G[u].push_back(v), G[v].push_back(u);
}
int mx = 0;
rep(i, 1, m) {
int x;
cin >> Op[i].op;
if (Op[i].op == 0)
cin >> Op[i].u >> Op[i].v >> Op[i].w, mx = max(mx, Op[i].w);
if (Op[i].op == 1)
cin >> x, Op[i].u = Op[x].u, Op[i].v = Op[x].v, Op[i].w = Op[x].w;
if (Op[i].op == 2)
cin >> Op[i].u, Op[i].id = ++tot;
id[i] = i;
}
DFS1(1, 0), DFS2(1, 1), Solve(1, mx + 1, 1, m);
rep(i, 1, tot)
cout << ans[i] << '\n';
return 0;
}