标签:gis dep getc 多源 pid font alc hnoi sdoi
板题,基本上是对着网上的板子敲的
#include <bits/stdc++.h> using namespace std; inline int read() { int out = 0; register char cc = getchar(); while (cc < ‘0‘ || cc > ‘9‘) cc = getchar(); while (cc >= ‘0‘ && cc <= ‘9‘) out = (out << 3) + (out << 1) + (cc ^ 48), cc = getchar(); return out; } inline void write(long long x) { if (x == 0) putchar(‘0‘); else { int num = 0; char c[20]; while (x) c[++num] = x % 10 + 48, x /= 10; while (num) putchar(c[num--]); } putchar(‘\n‘); } int N, M, K, a, b, c, Id[500010]; int head[500010], nxt[1000010], to[1000010], edge[1000010], cnt; void add_edge(int u, int v, int w) { to[++cnt] = v; edge[cnt] = w; nxt[cnt] = head[u]; head[u] = cnt; } void add(int u, int v) { to[++cnt] = v; nxt[cnt] = head[u]; head[u] = cnt; } int dfn[500010], tim; int f[500010][19], dep[500010]; long long Min[500010]; void dfs(int u, int fa) { dep[u] = dep[fa] + 1; f[u][0] = fa; dfn[u] = ++tim; for (int i = 1; i < 19; i++) f[u][i] = f[f[u][i - 1]][i - 1]; for (int i = head[u]; i; i = nxt[i]) { int v = to[i]; if (v == fa) continue; Min[v] = (Min[u] < edge[i] ? Min[u] : edge[i]); dfs(v, u); } } int Lca(int x, int y) { if (dep[x] < dep[y]) swap(x, y); for (int i = 18; i >= 0; i--) if (dep[f[x][i]] >= dep[y]) x = f[x][i]; if (x == y) return x; for (int i = 18; i >= 0; i--) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i]; return f[x][0]; } inline bool cmp(const int &g, const int &h) { return dfn[g] < dfn[h]; } int Stack[500010], tot; void Insert(int x) { if (tot == 1) { Stack[++tot] = x; return ; } int lca = Lca(x, Stack[tot]); if (lca == Stack[tot]) return ; while (tot > 1 && dfn[lca] <= dfn[Stack[tot - 1]]) add(Stack[tot - 1], Stack[tot]), tot--; if (lca != Stack[tot]) add(lca, Stack[tot]), Stack[tot] = lca; Stack[++tot] = x; } long long dp(int u) { long long ans = 0; for (int i = head[u]; i; i = nxt[i]) ans = ans + dp(to[i]); if (ans == 0) ans = 1LL << 60; head[u] = 0; return min(ans, Min[u]); } int main() { N = read(); for (int i = 1; i < N; i++) { a = read(), b = read(), c = read(); add_edge(a, b, c); add_edge(b, a, c); } Min[1] = 1LL << 60; dfs(1, 0); memset(head, 0, sizeof(head)); for (M = read(); M; M--) { K = read(), cnt = 0; for (int i = 1; i <= K; i++) Id[i] = read(); sort(Id + 1, Id + K + 1, cmp); Stack[tot = 1] = 1; for (int i = 1; i <= K; i++) Insert(Id[i]); while (tot) add(Stack[tot - 1], Stack[tot]), tot--; write(dp(1)); } return 0; }
虚树+树形DP+倍增
每次把议事处构成的虚树先建出来 $\Theta(\sum m_i\ log\ n)$
然后换根DP,求到每个虚树上的点的最近议事处 $\Theta(\sum m_i)$ (ps:你要多源最短路也行,慢一点)
最后对每条虚树上的边(实际在原树中为一条链),直接算出分界点(链上哪些属于上端,哪些属于下端),从下端点到上端点倍增即可 $\Theta(\sum m_i\ log\ n)$
思路挺简单的,细节对蒟蒻来说有一点点多
#include <bits/stdc++.h> using namespace std; inline int read() { int out = 0; bool flag = false; register char cc = getchar(); while (cc < ‘0‘ || cc > ‘9‘) { if (cc == ‘-‘) flag = true; cc = getchar(); } while (cc >= ‘0‘ && cc <= ‘9‘) { out = (out << 3) + (out << 1) + (cc ^ 48); cc = getchar(); } return flag ? -out : out; } inline void write(int x, char ch) { if (x < 0) putchar(‘-‘), x = -x; if (x == 0) putchar(‘0‘); else { int num = 0; char cc[22]; while (x) cc[++num] = x % 10 + 48, x /= 10; while (num) putchar(cc[num--]); } putchar(ch); } const int N = 3e5 + 10; int n, m, id[N], Id[N], ans[N]; int head[N], to[N << 1], nxt[N << 1], cnt; void add_edge(int u, int v) { to[++cnt] = v, nxt[cnt] = head[u], head[u] = cnt; } int dep[N], f[N][19], dfn[N], times, sze[N], s[N][19]; void dfs(int u, int fa) { dep[u] = dep[fa] + 1, f[u][0] = fa, dfn[u] = ++times; for (int i = 1; i <= 18; i++) f[u][i] = f[f[u][i - 1]][i - 1]; sze[u] = 1; for (int i = head[u]; i; i = nxt[i]) { int v = to[i]; if (v == fa) continue; dfs(v, u), sze[u] += sze[v]; } for (int i = head[u]; i; i = nxt[i]) { int v = to[i]; if (v == fa) continue; s[v][0] = sze[u] - sze[v]; } } void count(int u, int fa) { for (int i = 1; i <= 18; i++) s[u][i] = s[u][i - 1] + s[f[u][i - 1]][i - 1]; for (int i = head[u]; i; i = nxt[i]) { int v = to[i]; if (v == fa) continue; count(v, u); } } inline bool cmp(const int &g, const int &h) { return dfn[g] < dfn[h]; } int stk[N], tp, cl[N], tot; bool vis[N]; vector<int> son[N]; int Lca(int x, int y) { if (dep[x] < dep[y]) swap(x, y); for (int i = 18; i >= 0; i--) if (dep[f[x][i]] >= dep[y]) x = f[x][i]; if (x == y) return x; for (int i = 18; i >= 0; i--) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i]; return f[x][0]; } void ins(int x) { if (tp <= 1) return cl[++tot] = stk[++tp] = x, void(); int lca = Lca(x, stk[tp]); if (lca != stk[tp]) { while (tp > 1 && dfn[lca] <= dfn[stk[tp - 1]]) son[stk[tp - 1]].push_back(stk[tp]), tp--; if (lca != stk[tp]) son[lca].push_back(stk[tp]), cl[++tot] = stk[tp] = lca; } cl[++tot] = stk[++tp] = x; } int up[N], upid[N]; void pre(int u) { //cout << u << " "; if (vis[u]) up[u] = 0, upid[u] = u; else up[u] = 0x3f3f3f3f, upid[u] = 0x3f3f3f3f; for (int i = son[u].size() - 1; i >= 0; i--) { int v = son[u][i]; pre(v); if (up[u] > up[v] + dep[v] - dep[u] || (up[u] == up[v] + dep[v] - dep[u] && upid[u] > upid[v])) up[u] = up[v] + dep[v] - dep[u], upid[u] = upid[v]; } } int Min[N], Minid[N]; void dp(int u) { if (vis[u]) Min[u] = 0, Minid[u] = u; int fi = Min[u], se = 0x3f3f3f3f, fiid = Minid[u], seid = 0x3f3f3f3f; if (vis[u]) fi = 0, fiid = u; for (int i = son[u].size() - 1; i >= 0; i--) { int v = son[u][i]; if (fi > up[v] + dep[v] - dep[u] || (fi == up[v] + dep[v] - dep[u] && fiid > upid[v])) se = fi, seid = fiid, fi = up[v] + dep[v] - dep[u], fiid = upid[v]; else if (se > up[v] + dep[v] - dep[u] || (se == up[v] + dep[v] - dep[u] && seid > upid[v])) se = up[v] + dep[v] - dep[u], seid = upid[v]; } Min[u] = fi, Minid[u] = fiid; for (int i = son[u].size() - 1; i >= 0; i--) { int v = son[u][i]; if (up[v] + dep[v] - dep[u] == fi && upid[v] == fiid) Min[v] = se + dep[v] - dep[u], Minid[v] = seid; else Min[v] = fi + dep[v] - dep[u], Minid[v] = fiid; dp(v); } } int get(int u, int k) { int res = 0; for (int i = 18; i >= 0; i--) if (k >= (1 << i)) k -= (1 << i), res += s[u][i], u = f[u][i]; return res; } void calc(int u) { int sum = sze[u]; for (int i = son[u].size() - 1; i >= 0; i--) { int v = son[u][i]; calc(v); int k = dep[v] - dep[u] + Min[u] - Min[v]; int now = get(v, (k & 1) ? (k >> 1) : ((k >> 1) - (Minid[u] < Minid[v]))); sum -= (now + sze[v]), ans[Minid[v]] += now; } ans[Minid[u]] += sum; } int main() { n = read(); for (int i = 1; i < n; i++) { int u = read(), v = read(); add_edge(u, v), add_edge(v, u); } dfs(1, 0), count(1, 0); for (int T = read(); T; T--) { for (int i = 1; i <= tot; i++) son[cl[i]].clear(); for (int i = 1; i <= m; i++) vis[id[i]] = false; m = read(); for (int i = 1; i <= m; i++) vis[Id[i] = id[i] = read()] = true, ans[Id[i]] = 0; sort(id + 1, id + m + 1, cmp); tot = tp = 0; if (id[1] != 1) cl[tot = 1] = stk[tp = 1] = 1; for (int i = 1; i <= m; i++) ins(id[i]); while (tp > 1) son[stk[tp - 1]].push_back(stk[tp]), tp--; Min[1] = Minid[1] = 0x3f3f3f3f, pre(1), dp(1); calc(1); for (int i = 1; i <= m; i++) write(ans[Id[i]], ‘ ‘); putchar(‘\n‘); } return 0; }
标签:gis dep getc 多源 pid font alc hnoi sdoi
原文地址:https://www.cnblogs.com/Urushibara-Ruka/p/14455654.html