#define int long long #define Mid ((L+R) >> 1) constint N = 200010, M = 500010, K = 20; int n, m, q, fa[N][K], p[N], h[N], w[N], l[N], r[N], krt; int rt[N], ls[N*K], rs[N*K], cnt[N*K], idx; int ch[N][2], deg[N], ts;
voidadd(int a, int b){ deg[b]++; if (!ch[a][0]) ch[a][0] = b; else ch[a][1] = b; }
voidread(int& t){ t = 0; char ch = getchar(); while (!isdigit(ch)) ch = getchar(); while (isdigit(ch)) t = t*10 + (ch^48), ch = getchar(); }
structEdge { int a, b, c; booloperator<(const Edge& e) const { return c < e.c; } } edge[M];
voidinsert(int& u, int v, int p, int L = 0, int R = 1e9){ u = ++idx; ls[u] = ls[v], rs[u] = rs[v], cnt[u] = cnt[v] + 1; if (L == R) return; if (p <= Mid) insert(ls[u], ls[v], p, L, Mid); elseinsert(rs[u], rs[v], p, Mid+1, R); }
intquery(int u, int v, int k, int L = 0, int R = 1e9){ if (L == R) return L; int c = cnt[rs[u]] - cnt[rs[v]]; if (k <= c) returnquery(rs[u], rs[v], k, Mid+1, R); elsereturnquery(ls[u], ls[v], k-c, L, Mid); }
voidkruskal(){ krt = n; sort(edge+1, edge+1+m); for (int i = 1; i <= n<<1; i++) p[i] = i; for (int i = 1; i <= m; i++) { int a = edge[i].a, b = edge[i].b, c = edge[i].c; int pa = find(a), pb = find(b); if (pa == pb) continue; p[pa] = p[pb] = ++krt, w[krt] = c; add(krt, pa), add(krt, pb); } w[0] = 1e18; }
voiddfs(int u, int f){ fa[u][0] = f; for (int k = 1; k < K; k++) fa[u][k] = fa[fa[u][k-1]][k-1]; if (!ch[u][0]) { l[u] = r[u] = ++ts; insert(rt[ts], rt[ts-1], h[u]); return; } dfs(ch[u][0], u), dfs(ch[u][1], u); l[u] = min(l[ch[u][0]], l[ch[u][1]]); r[u] = max(r[ch[u][0]], r[ch[u][1]]); }
signedmain(){ read(n), read(m), read(q); for (int i = 1; i <= n; i++) read(h[i]); for (int i = 1, a, b, c; i <= m; i++) read(a), read(b), read(c), edge[i] = {a, b, c}; kruskal(); for (int i = 1; i <= krt; i++) if (!deg[i]) dfs(i, 0);
int last = 0; for (int i = 1, u, x, k; i <= q; i++) { read(u), read(x), read(k); x ^= last; u = (u ^ last) % n + 1; k = (k ^ last) % n + 1; for (int k = K-1; k >= 0; k--) { if (w[fa[u][k]] <= x) u = fa[u][k]; } int L = rt[l[u]-1], R = rt[r[u]]; if (cnt[R] - cnt[L] < k) puts("-1"), last = 0; elseprintf("%lld\n", last = query(R, L, k)); }
return0; }
[CF1706E] Qpwoeirut and Vertices
多测,给出 n 个点, m 条边的不带权连通无向图, q 次询问至少要加完编号前多少的边,才能使得 [l,r] 中的所有点两两连通。
constint N = 200010, K = 20; int n, m, q, ts, ch[N][2], dep[N], l[N], r[N], p[N], deg[N], dfn[N], pos[N], w[N]; int fa[K][N], st1[K][N], st2[K][N], lg2[N];
voidread(int& t){ t = 0; char ch = getchar(); while (!isdigit(ch)) ch = getchar(); while (isdigit(ch)) t = t*10 + (ch^48), ch = getchar(); }
intlca(int a, int b){ if (dep[a] < dep[b]) swap(a, b); for (int k = K-1; k >= 0; k--) if (dep[fa[k][a]] >= dep[b]) a = fa[k][a]; if (a == b) return a; for (int k = K-1; k >= 0; k--) if (fa[k][a] != fa[k][b]) a = fa[k][a], b = fa[k][b]; return fa[0][a]; }
voidsolve(){ ts = 0; read(n), read(m), read(q); for (int i = 1; i <= 2*n; i++) p[i] = i, ch[i][0] = ch[i][1] = deg[i] = w[i] = fa[0][i] = 0; // Kruskal Tree int krt = n; for (int i = 1, a, b, pa, pb; i <= m; i++) { read(a), read(b); pa = find(a), pb = find(b); if (pa == pb) continue; w[++krt] = i; p[pa] = p[pb] = krt; fa[0][pa] = fa[0][pb] = krt; ch[krt][0] = pa, ch[krt][1] = pb; ++deg[pa], ++deg[pb]; } l[0] = -1, r[0] = N;
for (int i = 1; i <= krt; i++) if (!deg[i]) dfs(i); for (int k = 1; k < K; k++) for (int i = 1; i <= krt; i++) fa[k][i] = fa[k-1][fa[k-1][i]];
// Sprase Table for (int k = 0; k < K; k++) { for (int i = 1; i+(1<<k)-1 <= n; i++) { if (!k) st1[k][i] = st2[k][i] = dfn[i]; else st1[k][i] = min(st1[k-1][i], st1[k-1][i+(1<<(k-1))]), st2[k][i] = max(st2[k-1][i], st2[k-1][i+(1<<(k-1))]); } }
for (int i = 1, a, b, k, u, L, R; i <= q; i++) { read(a), read(b); k = lg2[b-a+1]; L = min(st1[k][a], st1[k][b-(1<<k)+1]); R = max(st2[k][a], st2[k][b-(1<<k)+1]); printf("%d", w[lca(pos[L], pos[R])]); putchar(" \n"[i == q]); } }
intmain(){ lg2[1] = 0; for (int i = 2; i < N; i++) lg2[i] = lg2[i>>1] + 1;
voidbuild(int u, int L, int R){ mn1[u] = INF, mx1[u] = -INF; if (L == R) return mn2[u] = mx2[u] = dfn[L], void(); build(u<<1, L, Mid), build(u<<1|1, Mid+1, R); mn2[u] = min(mn2[u<<1], mn2[u<<1|1]), mx2[u] = max(mx2[u<<1], mx2[u<<1|1]); }
voidmodify(int u, int l, int r, int k, int L, int R){ if (l <= L && R <= r) returnspread(u, k); pushdown(u); if (l <= Mid) modify(u<<1, l, r, k, L, Mid); if (Mid+1 <= r) modify(u<<1|1, l, r, k, Mid+1, R); pushup(u); }
voiddfs(int u){ dep[u] = dep[fa[0][u]] + 1; if (!ch[u][0]) return dfn[u] = ++ts, pos[ts] = u, void(); dfs(ch[u][0]), dfs(ch[u][1]); }
intlca(int a, int b){ if (dep[a] < dep[b]) swap(a, b); for (int k = K-1; k >= 0; k--) if (dep[fa[k][a]] >= dep[b]) a = fa[k][a]; if (a == b) return a; for (int k = K-1; k >= 0; k--) if (fa[k][a] != fa[k][b]) a = fa[k][a], b = fa[k][b]; return fa[0][a]; }
intmain(){ read(n), read(q); for (int i = 1, a, b, c; i < n; i++) read(a), read(b), read(c), edge[i] = {a, b, c}; sort(edge+1, edge+n);
int krt = n; for (int i = 1; i <= 2*n; i++) p[i] = i; for (int i = 1; i < n; i++) { int a = edge[i].a, b = edge[i].b, c = edge[i].c; int pa = find(a), pb = find(b); if (pa == pb) continue; p[pa] = p[pb] = fa[0][pa] = fa[0][pb] = ++krt; w[krt] = c; ch[krt][0] = pa, ch[krt][1] = pb; ++deg[pa], ++deg[pb]; } for (int i = 1; i <= krt; i++) if (!deg[i]) dfs(i); for (int k = 1; k < K; k++) for (int i = 1; i <= krt; i++) fa[k][i] = fa[k-1][fa[k-1][i]]; build(1, 1, n);
for (int i = 1, opt, x, l, r; i <= q; i++) { read(opt); if (opt != 3) read(l), read(r), modify(1, l, r, opt, 1, n); else { read(x); int L = mn1[1], R = mx1[1], ans = -1; if (L != INF && R != -INF) { int u = lca(pos[L], pos[R]); if (u != x) ans = w[lca(u, x)]; } printf("%d\n", ans); } } return0; }
[IOI2018] 狼人
在日本的茨城县内共有 N 个城市和 M 条道路。这些城市是根据人口数量的升序排列的,依次编号为 0 到 N−1。每条道路连接两个不同的城市,并且可以双向通行。由这些道路,你能从任意一个城市到另外任意一个城市。
voiddfs(int u){ for (int k = 1; k < K; k++) fa[u][k] = fa[fa[u][k-1]][k-1]; if (!ch[u][0]) { dfn[u] = ++ts; l[u] = r[u] = ts; return; } dfs(ch[u][0]), dfs(ch[u][1]); l[u] = l[ch[u][0]], r[u] = r[ch[u][1]]; }
voidbuild(int w0){ int rt = n;
for (int i = 1; i <= n<<1; i++) p[i] = i; for (int i = 1; i <= m; i++) { int a = edge[i].a, b = edge[i].b, c = edge[i].c; int pa = find(a), pb = find(b); if (pa == pb) continue; p[pa] = p[pb] = ++rt; w[rt] = c; ch[rt][0] = pa, ch[rt][1] = pb, fa[pa][0] = fa[pb][0] = rt; ++deg[pa], ++deg[pb]; }
for (int i = 1; i <= rt; i++) if (!deg[i]) dfs(i); w[0] = w0; for (int i = 1; i <= n; i++) rev[dfn[i]] = i; }
voidqueryr(int& a, int& b, int u, int v){ for (int k = K-1; k >= 0; k--) { if (w[fa[u][k]] <= v) u = fa[u][k]; } a = l[u], b = r[u]; }
voidqueryl(int& a, int& b, int u, int v){ for (int k = K-1; k >= 0; k--) { if (w[fa[u][k]] >= v) u = fa[u][k]; } a = l[u], b = r[u]; } } k2, k1;
voidinsert(int& u, int v, int p, int L, int R){ u = ++idx; ls[u] = ls[v], rs[u] = rs[v], cnt[u] = cnt[v] + 1; if (L == R) return; if (p <= Mid) insert(ls[u], ls[v], p, L, Mid); elseinsert(rs[u], rs[v], p, Mid+1, R); }
intquery(int u, int v, int l, int r, int L, int R){ if (l <= L && R <= r) return cnt[u] - cnt[v]; int res = 0; if (l <= Mid) res = query(ls[u], ls[v], l, r, L, Mid); if (Mid+1 <= r) res += query(rs[u], rs[v], l, r, Mid+1, R); return res; }
intmain(){ read(n), read(m), read(q); for (int i = 1, a, b; i <= m; i++) read(a), read(b), ++a, ++b, edge[i] = {a, b};
for (int i = 1; i <= m; i++) edge[i].c = min(edge[i].a, edge[i].b); sort(edge+1, edge+1+m, [](const Edge& a, const Edge& b){ return a.c > b.c; }); k1.build(0);
for (int i = 1; i <= m; i++) edge[i].c = max(edge[i].a, edge[i].b); sort(edge+1, edge+1+m, [](const Edge& a, const Edge& b){ return a.c < b.c; }); k2.build(N);
for (int i = 1; i <= n; i++) insert(rt[i], rt[i-1], k2.dfn[k1.rev[i]], 1, n);
for (int i = 1, s, e, l, r; i <= q; i++) { read(s), read(e), read(l), read(r); ++s, ++e, ++l, ++r; int l1, r1, l2, r2; k1.queryl(l1, r1, s, l); k2.queryr(l2, r2, e, r); if (query(rt[r1], rt[l1-1], l2, r2, 1, n)) puts("1"); elseputs("0"); } return0; }