洛谷 P2495 [SDOI2011] 消耗战
每次询问都对整棵树dp的话会超时,发现询问的点总和较少,可以每次询问都建立一棵虚树,对这棵虚树进行dp
建立虚树就是只保留对答案可能有贡献的结点,即保留目标岛屿和目标岛屿的lca
#include<bits/stdc++.h>
using namespace std;
#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false),cin.tie(0);
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef unsigned long long ULL;
const int INF = 0X3f3f3f3f, N = 1e6 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);
int n, m;
int idx, head[N];
int stk[N], tt;
LL mn[N];
vector<int> g[N];
struct EDGE {
int to, next, w;
} eg[N];
void add(int x, int y, int w) {
eg[idx].to = y;
eg[idx].next = head[x];
eg[idx].w = w;
head[x] = idx++;
}
void _add(int x, int y) {
g[x].push_back(y);
}
//Heavy-light Decomposition STARTS FORM HERE
int siz[N];//number of son
int son[N];//heavy son of the node
int faz[N];//father of the node
int dep[N];//depth of the node
int top[N];//top of the heavy link
int dfn[N];//ID -> DFSID
int rnk[N];//DFSID -> ID
int cnt;//时间戳
void dfs_1(int cur, int fa, int depth) {
siz[cur] = 1;
faz[cur] = fa;
dep[cur] = depth;
for(int i = head[cur]; ~i; i = eg[i].next) {
int to = eg[i].to;
if (to == fa) continue;
mn[to] = min(mn[cur], 1ll * eg[i].w);
dfs_1(to, cur, depth + 1);
siz[cur] += siz[to];
if (son[cur] == -1 || siz[son[cur]] < siz[to]) son[cur] = to;
}
}
void dfs_2(int cur, int tp) {
top[cur] = tp;
dfn[cur] = ++cnt;
rnk[cnt] = cur;
if (son[cur] == -1) return;
dfs_2(son[cur], tp);
for (int i = head[cur]; ~i; i = eg[i].next) {
int to = eg[i].to;
if (to != son[cur] && to != faz[cur]) dfs_2(to, to);
}
}
int get_lca(int x, int y) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) y = faz[top[y]];
else x = faz[top[x]];
}
if (dep[x] < dep[y]) return x;
else return y;
}
bool cmp(int x, int y) {
return dfn[x] < dfn[y];
}
void insert(int x) {
if (stk[tt] == 1) {
stk[++tt] = x;
return;
}
int lca = get_lca(x, stk[tt]);
if (lca == stk[tt]) return;
while (tt > 1 && dfn[stk[tt - 1]] >= dfn[lca]) _add(stk[tt - 1], stk[tt]), tt--;
if (lca != stk[tt]) _add(lca, stk[tt]), stk[tt] = lca;
stk[++tt] = x;
}
LL dp(int u) {
cout << u << " ";
LL sum = 0;
if (g[u].size() == 0) sum = mn[u];
rep (i, 0, g[u].size() - 1) sum += dp(g[u][i]);
g[u].clear();
return min(mn[u], sum);
}
void work() {
mn[1] = 1ll << 60;
memset(son, -1, sizeof son);
memset(head, -1, sizeof head);
cin >> n;
rep (i, 1, n - 1) {
int x, y, w;
cin >> x >> y >> w;
add(x, y, w), add(y, x, w);
}
dfs_1(1, 0, 0), dfs_2(1, 1);
cin >> m;
while (m--) {
int k;
cin >> k;
vector<int> tmp(k + 1);
rep (i, 1, k) cin >> tmp[i];
sort(tmp.begin() + 1, tmp.begin() + 1 + k, cmp);
stk[tt = 1] = 1;
rep (i, 1, k) insert(tmp[i]);
while (tt > 0) _add(stk[tt - 1], stk[tt]), tt--;
cout << dp(1) << endl;
}
}
signed main() {
IO
int test = 1;
while (test--) {
work();
}
return 0;
}

浙公网安备 33010602011771号