洛谷 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;
}

posted @ 2022-09-06 19:41  xhy666  阅读(52)  评论(0)    收藏  举报