#define Mid ((L+R) >> 1) constint N = 200010, K = 20; int n, m, rt[N], a[N], nums[N], cntnums; int ls[N*K], rs[N*K], cnt[N*K]; int idx;
voidinsert(int u, int v, int k, int L, int R){ cnt[u] = cnt[v] + 1, ls[u] = ls[v], rs[u] = rs[v]; if (L == k && R == k) return; if (k <= Mid) ls[u] = ++idx, insert(ls[u], ls[v], k, L, Mid); else rs[u] = ++idx, insert(rs[u], rs[v], k, Mid+1, R); }
intquery(int u, int v, int k, int L, int R){ if (L == R) return L; int c = cnt[ls[v]] - cnt[ls[u]]; if (k <= c) returnquery(ls[u], ls[v], k, L, Mid); elsereturnquery(rs[u], rs[v], k-c, Mid+1, R); }
intquery(int a, int b, int c, int d, int k, int L, int R){ if (L == R) return L; int tot = cnt[ls[a]] + cnt[ls[b]] - cnt[ls[c]] - cnt[ls[d]]; if (k <= tot) returnquery(ls[a], ls[b], ls[c], ls[d], k, L, Mid); elsereturnquery(rs[a], rs[b], rs[c], rs[d], k - tot, Mid+1, R); } } T;
voiddfs(int u, int f){ rt[u] = ++T.idx; T.insert(rt[u], rt[f], w[u], 1, len); fa[u][0] = f, dep[u] = dep[f] + 1; for (int k = 1; k < K; k++) fa[u][k] = fa[fa[u][k-1]][k-1]; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == f) continue; dfs(to, u); } }
intlca(int a, int b){ if (dep[a] < dep[b]) swap(a, b); for (int k = K-1; k >= 0; k--) if (dep[fa[a][k]] >= dep[b]) a = fa[a][k]; if (a == b) return a; for (int k = K-1; k >= 0; k--) if (fa[a][k] != fa[b][k]) a = fa[a][k], b = fa[b][k]; return fa[a][0]; }
intmain(){ read(n), read(m); for (int i = 1; i <= n; i++) read(w[i]), nums[i] = w[i]; sort(nums+1, nums+1+n); len = unique(nums+1, nums+1+n) - (nums+1); for (int i = 1; i <= n; i++) w[i] = lower_bound(nums+1, nums+1+len, w[i]) - nums; for (int i = 1, a, b; i < n; i++) { read(a), read(b); add(a, b), add(b, a); } dfs(1, 0);
int lastans = 0; for (int i = 1, u, v, k; i <= m; i++) { read(u), read(v), read(k); u ^= lastans; int l = lca(u, v); lastans = nums[T.query(rt[u], rt[v], rt[l], rt[fa[l][0]], k, 1, len)]; printf("%d\n", lastans); }
return0; }
Mex
给定 n 个元素的数组 a,m 次询问 [l,r] 的最小没有出现过的自然数。1≤n,m,ai≤2×105。
#define Mid ((L+R) >> 1) constint N = 200010, M = 20*N;
int n, m, rt[N], ls[M], rs[M], val[M], idx;
voidupdate(int& u, int v, int p, int k, int L = 0, int R = 2e5){ u = ++idx, ls[u] = ls[v], rs[u] = rs[v]; if (L == R) return val[u] = k, void(); if (p <= Mid) update(ls[u], ls[v], p, k, L, Mid); elseupdate(rs[u], rs[v], p, k, Mid+1, R); val[u] = min(val[ls[u]], val[rs[u]]); }
intquery(int u, int k, int L = 0, int R = 2e5){ if (L == R) return L; if (val[ls[u]] <= k) returnquery(ls[u], k, L, Mid); elsereturnquery(rs[u], k, Mid+1, R); }
intmain(){ scanf("%d%d", &n, &m); for (int i = 1, a; i <= n; i++) { scanf("%d", &a); update(rt[i], rt[i-1], a, i); } for (int i = 1, l, r; i <= m; i++) { scanf("%d%d", &l, &r); printf("%d\n", query(rt[r], l-1)); } return0; }
[十二省联考 2019] 异或粽子
小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。
小粽面前有 n 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 1 到 n。第 i 种馅儿具有一个非负整数的属性值 ai。每种馅儿的数量都足够多,即小粽不会因为缺少原料而做不出想要的粽子。小粽准备用这些馅儿来做出 k 个粽子。
voidinsert(int& u, int v, int bits, int k, int ident){ u = clone(v), ++cnt[u]; if (bits == -1) return id[u] = ident, void(); int b = k >> bits & 1; insert(tr[u][b], tr[v][b], bits-1, k, ident); }
intquery(int u, int v, int bits, int k){ if (bits == -1) return id[v]; int b = k >> bits & 1; if (cnt[tr[v][b^1]] - cnt[tr[u][b^1]] > 0) returnquery(tr[u][b^1], tr[v][b^1], bits-1, k); returnquery(tr[u][b], tr[v][b], bits-1, k); }
signedmain(){ read(n), read(k);
insert(rt[-1], 0, 31, 0, -1); insert(rt[0], rt[-1], 31, 0, 0); for (int i = 1, a; i <= n; i++) { read(a); insert(rt[i], rt[i-1], 31, s[i] = s[i-1] ^ a, i); } priority_queue<Range> heap; for (int i = 1; i <= n; i++) { int id = query(rt[-1], rt[i-1], 31, s[i]); heap.push({0, i-1, id, s[i], s[i] ^ s[id]}); }
int sum = 0; while (k--) { Range rg = heap.top(); heap.pop(); sum += rg.val; if (rg.l < rg.k) { int id = query(rt[rg.l-1], rt[rg.k-1], 31, rg.raw); heap.push({rg.l, rg.k-1, id, rg.raw, rg.raw ^ s[id]}); }
if (rg.k < rg.r) { int id = query(rt[rg.k], rt[rg.r], 31, rg.raw); heap.push({rg.k+1, rg.r, id, rg.raw, rg.raw ^ s[id]}); } }
printf("%lld\n", sum); return0; }
[NOI2018] 归程
本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定。
魔力之都可以抽象成一个 n 个节点、m 条边的无向连通图(节点的编号从 1 至 n)。我们依次用 l,a 描述一条边的长度、海拔。
while (!heap.empty()) { int t = heap.top().se; heap.pop(); if (st[t]) continue; st[t] = true; for (int i = h[t]; i; i = e[i].nxt) { int to = e[i].to; if (dist[to] > dist[t] + e[i].w) { dist[to] = dist[t] + e[i].w; heap.push({dist[to], to}); } } } }
SGT::Node find(int rt, int x){ SGT::Node nd; while ((nd = T.query(rt, x, 1, n)).fa != x) { x = T.query(rt, x, 1, n).fa; } return nd; }
dsu.init(n); T.rt[0] = T.build(1, n); for (int i = 1; i <= m; i++) { T.rt[i] = T.rt[i-1]; int a = dsu.find(edge[i].a), b = dsu.find(edge[i].b); if (a == b) continue; SGT::Node& A = T.update(T.rt[i], a, 1, n), &B = T.update(T.rt[i], b, 1, n); if (A.sz <= B.sz) { A.fa = b; B.sz += A.sz; B.dis = min(A.dis, B.dis); dsu.merge(a, b); } else { B.fa = a; A.sz += B.sz; A.dis = min(A.dis, B.dis); dsu.merge(b, a); } } }
voidsolve(){ read(n), read(m); idx = 2; for (int i = 1; i <= n; i++) dist[i] = INF, st[i] = h[i] = 0; for (int i = 1, a, b, c, h; i <= m; i++) { read(a), read(b), read(c), read(h); add(a, b, c), add(b, a, c); edge[i] = {a, b, h}; } initdsu(); edge[0].h = INF;
int lastans = 0, Q, K, S, v, p; read(Q), read(K), read(S); while (Q--) { read(v), read(p); v = (v + K*lastans - 1) % n + 1; p = (p + K*lastans) % (S+1);
int l = 0, r = m; while (l < r) { int mid = (l+r+1) >> 1; if (edge[mid].h > p) l = mid; else r = mid-1; } SGT::Node nd = find(T.rt[r], v); printf("%lld\n", lastans = nd.dis); } }
signedmain(){ int T; read(T); while (T--) solve(); return0; }
[USACO19DEC] Milk Visits G
Farmer John 计划建造 N 个农场,用 N−1 条道路连接,构成一棵树(也就是说,所有农场之间都互相可以到达,并且没有环)。每个农场有一头奶牛,品种为 1 到 N 之间的一个整数 Ti。
Farmer John 的 M 个朋友经常前来拜访他。在朋友 i 拜访之时,Farmer John 会与他的朋友沿着从农场 Ai 到农场 Bi 之间的唯一路径行走(可能有 Ai=Bi)。除此之外,他们还可以品尝他们经过的路径上任意一头奶牛的牛奶。由于 Farmer John 的朋友们大多数也是农场主,他们对牛奶有着极强的偏好。他的每个朋友都只喝某种特定品种的奶牛的牛奶。任何 Farmer John 的朋友只有在他们访问时能喝到他们偏好的牛奶才会高兴。
#define Mid ((L+R) >> 1) constint N = 100010, M = 20*N; int n, q, rt[N], a[N], dfna[N], cnt[M], ls[M], rs[M], idx; int h[N], fa[N], top[N], dep[N], dfn[N], sz[N], son[N], ts, tot = 2; char ans[N]; structEdge { int to, nxt; } e[N<<1];
voidadd(int a, int b){ e[tot] = {b, h[a]}, h[a] = tot++; }
voidinsert(int& u, int v, int p, int L, int R){ u = ++idx; cnt[u] = cnt[v] + 1, ls[u] = ls[v], rs[u] = rs[v]; 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 p, int L, int R){ if (L == R) return cnt[u] - cnt[v]; if (p <= Mid) returnquery(ls[u], ls[v], p, L, Mid); elsereturnquery(rs[u], rs[v], p, Mid+1, R); }
voiddfs1(int u, int f){ sz[u] = 1, fa[u] = f, dep[u] = dep[f] + 1; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == f) continue; dfs1(to, u); sz[u] += sz[to]; if (sz[son[u]] < sz[to]) son[u] = to; } }
voiddfs2(int u, int t){ top[u] = t, dfn[u] = ++ts, dfna[ts] = a[u]; if (!son[u]) return; dfs2(son[u], t); for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == son[u] || to == fa[u]) continue; dfs2(to, to); } }
intquerypath(int a, int b, int c){ while (top[a] != top[b]) { if (dep[top[a]] < dep[top[b]]) swap(a, b); if (query(rt[dfn[a]], rt[dfn[top[a]]-1], c, 1, n)) return1; a = fa[top[a]]; } if (dfn[a] > dfn[b]) swap(a, b); returnquery(rt[dfn[b]], rt[dfn[a]-1], c, 1, n) > 0; }
intmain(){ scanf("%d%d", &n, &q); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1, a, b; i < n; i++) scanf("%d%d", &a, &b), add(a, b), add(b, a); dfs1(1, 0); dfs2(1, 1); for (int i = 1; i <= n; i++) insert(rt[i], rt[i-1], dfna[i], 1, n); for (int i = 1, a, b, c; i <= q; i++) { scanf("%d%d%d", &a, &b, &c); ans[i] = querypath(a, b, c) ^ 48; } printf("%s\n", ans+1); return0; }