zoukankan      html  css  js  c++  java
  • luoguP2495 [SDOI2011]消耗战

    https://www.luogu.org/problemnew/show/P2495

    Dp 方程很显然

    设 Dp[u] 表示——使 u 不与其子树中任意一个关键点联通的最小代价

    设 w[a, b] 表示 a 与 b 之间的边的权值。

    • 若 son[i] 不是关键点,Dp[u] = Dp[u] + min{Dp[son[i]],w[u][son[i]]}
    • 若 son[i] 是关键点,Dp[u] = Dp[u] + w[u][son[i]]

    但这样复杂度很显然是不对的,所以我们考虑虚树

    什么,你还不会虚树?那就去跟 zzq 学吧 https://www.cnblogs.com/zzqsblog/p/5560645.html

    我们发现 k 的总和与 n 同级,所以用虚树优化这个 Dp,建出虚树,在虚树上 Dp 即可

    #include <bits/stdc++.h>
    #define X first
    #define Y second
    #define mp make_pair
    using namespace std;
    
    typedef long long ll;
    const int N = 250000 + 5, LG2 = 18;
    
    vector < pair <int, int> > G[N], G2[N];
    int pre[N][LG2 + 1], dep[N], mx[N][LG2 + 1], id[N], dfn;
    int n, m, k, h[N], sta[N], len, MX;
    ll f[N];
    bool book[N];
    
    void init(int u, int fa) {
    	pre[u][0] = fa; dep[u] = dep[fa] + 1; id[u] = ++dfn;
    	for(int i = 1; i <= LG2; i++) {
    		pre[u][i] = pre[pre[u][i - 1]][i - 1];
    		mx[u][i] = min(mx[u][i - 1], mx[pre[u][i - 1]][i - 1]);
    	}
    	for(vector < pair <int, int> > :: iterator it = G[u].begin(); it != G[u].end(); it++) {
    		int v = it -> X; if(v != fa) mx[v][0] = it -> Y, init(v, u);
    	}
    }
    
    int LCA(int x, int y) {
    	MX = INT_MAX;
    	if(dep[x] > dep[y]) swap(x, y);
    	for(int i = LG2; i >= 0; i--)
    		if(dep[pre[y][i]] >= dep[x])
    			MX = min(MX, mx[y][i]), y = pre[y][i];
    	if(x == y) return x;
    	for(int i = LG2; i >= 0; i--)
    		if(pre[x][i] != pre[y][i]) {
    			MX = min(MX, min(mx[x][i], mx[y][i]));
    			x = pre[x][i], y = pre[y][i];
    		}
    	return pre[x][0];
    }
    
    bool cmp(int x, int y) {return id[x] < id[y];}
    
    void DP(int u) {
    	f[u] = 0;
    	for(vector < pair <int, int> > :: iterator it = G2[u].begin(); it != G2[u].end(); it++) {
    		int v = it -> X; DP(v);
    		if(book[v]) f[u] += it -> Y;
    		else f[u] += min(f[v], (ll)it -> Y);
    	}
    }
    
    int main() {
    	cin >> n;
    	for(int i = 1; i < n; i++) {
    		int a, b, c;
    		scanf("%d %d %d", &a, &b, &c);
    		G[a].push_back( mp(b, c) );
    		G[b].push_back( mp(a, c) ); 
    	}
    	init(1, 0); cin >> m;
    	while(m--) {
    		scanf("%d", &k);
    		for(int i = 1; i <= k; i++) {
    			scanf("%d", &h[i]);
    			book[h[i]] = 1;
    		}
    		sort(h + 1, h + k + 1, cmp);
    		sta[len = 1] = 1; G2[1].clear();
    		for(int i = 1; i <= k; i++) {
    			if(h[i] == 1) continue;
    			int lca = LCA(h[i], sta[len]);
    			if(lca != sta[len]) {
    				while(id[lca] < id[sta[len - 1]]) {
    					LCA(sta[len - 1], sta[len]);
    					G2[sta[len - 1]].push_back( mp(sta[len], MX) );
    					len--;
    				}
    				if(id[lca] > id[sta[len - 1]]) {
    					G2[lca].clear();
    					LCA(lca, sta[len]);
    					G2[lca].push_back( mp(sta[len], MX) );
    					sta[len] = lca;
    				} else LCA(lca, sta[len]), G2[lca].push_back( mp(sta[len], MX) ), len--;
    			}
    			G2[h[i]].clear(); sta[++len] = h[i];
    		}
    		for(int i = 1; i < len; i++) LCA(sta[i], sta[i + 1]), G2[sta[i]].push_back( mp(sta[i + 1], MX) );
    		DP(1); printf("%lld
    ", f[1]);
    		for(int i = 1; i <= k; i++) book[h[i]] = 0;
    	}
    	return 0;
    }
    
  • 相关阅读:
    PAT顶级 1015 Letter-moving Game (35分)
    PAT顶级 1008 Airline Routes (35分)(有向图的强连通分量)
    PAT顶级 1025 Keep at Most 100 Characters (35分)
    PAT顶级 1027 Larry and Inversions (35分)(树状数组)
    PAT 顶级 1026 String of Colorful Beads (35分)(尺取法)
    PAT顶级 1009 Triple Inversions (35分)(树状数组)
    Codeforces 1283F DIY Garland
    Codeforces Round #438 A. Bark to Unlock
    Codeforces Round #437 E. Buy Low Sell High
    Codeforces Round #437 C. Ordering Pizza
  • 原文地址:https://www.cnblogs.com/LJC00118/p/9612518.html
Copyright © 2011-2022 走看看