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

    Pre

    开始的时候不叫 (O2) 的话 (60) 分,加了 (O2)(50) 分。。。

    Solution

    直接虚树,本文目的在于说明易错点。

    Code

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <limits.h>
    #define ll long long
    using namespace std;
    
    struct _in {
    	const _in operator , (ll & a) const {
    		a = 0;
    		char k = getchar ();
    		while (k > '9' || k < '0') k = getchar ();
    		while (k >= '0' && k <= '9') {
    			a = a * 10 + k - '0';
    			k = getchar ();
    		}
    		return * this;
    	}
    }in;
    inline void swap (int&u, int&v) {
    	int c = u;
    	u = v,
    	v = c;
    }
    inline int min (int u, int v) {
    	return u > v ? v : u;
    }
    inline ll min (ll u, ll v) {
    	return u > v ? v : u;
    }
    const int N = 250000 + 5;
    int n, dfn[N], dftot;
    int m, dep[N], st[N][20];
    ll sts[N][20], cnt, k[N];
    bool cmp (int u, int v) {
    	return dfn[u] < dfn[v];
    }
    struct ECH {
    	int tme[N], now;
    	bool rch[N];
    	inline void init () {
    		++now;
    	}
    	inline void insert (int p) {
    		tme[p] = now, rch[p] = 1;
    	}
    	inline bool query (int p) {
    		if (tme[p] != now) tme[p] = now, rch[p] = 0;
    		else return rch[p];
    		return 0;
    	}
    }rch;
    struct Graph {
    	int fr[N << 1], to[N << 1], h[N], tot;
    	ll val[N << 1];
    	inline void add (int u, int v, ll w) {
    		tot++;
    		fr[tot] = h[u];
    		to[tot] = v;
    		h[u] = tot;
    		val[tot] = w;
    	}
    	inline void dfs (int u, int f) {
    		dfn[u] = ++dftot;
    		dep[u] = dep[f] + 1;
    		st[u][0] = f;
    		for (int i = 1; i <= 18; ++i) st[u][i] = st[ st[u][i - 1] ][i - 1];
    		for (int i = 1; i <= 18; ++i) sts[u][i] = min (sts[u][i - 1], sts[ st[u][i - 1] ][i - 1]);
    		for (int i = h[u]; i; i = fr[i]) {
    			if (to[i] == f) continue;
    			sts[ to[i] ][0] = val[i];
    			dfs (to[i], u);
    		}
    	}
    	inline int lca (int u, int v) {
    		if (dep[u] < dep[v]) swap (u, v);
    		for (int i = 19; i >= 0 && dep[u] != dep[v]; --i)
    			if (dep[ st[u][i] ] >= dep[v]) u = st[u][i];
    		for (int i = 19; i >= 0; --i)
    			if (st[u][i] != st[v][i]) u = st[u][i], v = st[v][i];
    		if (u == v) return u;
    		else return st[u][0];
    	}
    	inline ll query (int u, int v) {
    		ll res = INT_MAX;
    		if (dep[u] < dep[v]) swap (u, v);
    		for (int i = 18; i >= 0 && u != v; --i)
    			if (st[u][i] != v) res = min (res, sts[u][i]), u = st[u][i];
    		if (u != v) res = min (res, sts[u][0]);
    		return res;
    	}
    }g1;
    struct Graph2 {
    	int stk[N], top;
    	ll dp[N];
    	inline void init () {
    		top = 0;
    	}
    	inline void build () {
    		for (int i = 1; i <= cnt; ++i) {
    			dp[ k[i] ] = 0;
    			int v = k[i];
    			if (!top) { stk[++top] = v; continue; }
    			else {
    				int lca = g1.lca (v, stk[top]);
    				if (lca == stk[top]) {
    					stk[++top] = v;
    					continue;
    				}
    				while (1) {
    					if (dep[lca] > dep[ stk[top - 1] ]) {
    						dp[lca] = 0;
    						ll wt = g1.query(lca, stk[top]);
    						if (rch.query(stk[top])) dp[lca] += wt;
    						else dp[lca] += min (wt, dp[stk[top]]);
    						stk[top] = lca, stk[++top] = v;
    						break;
    					}
    					else if (dep[lca] == dep[ stk[top - 1] ]) {
    						ll wt = g1.query(lca, stk[top]);
    						if (rch.query(stk[top])) dp[lca] += wt;
    						else dp[lca] += min (wt, dp[stk[top]]);
    						stk[top] = v;
    						break;
    					}
    					else {
    						ll wt = g1.query(stk[top - 1], stk[top]);
    						if (rch.query(stk[top])) dp[ stk[top - 1] ] += wt;
    						else dp[ stk[top - 1] ] += min (wt, dp[ stk[top] ]);
    						top--;
    					}
    				}
    			}
    		}
    		while (top > 1) {
    			ll wt = g1.query(stk[top], stk[top - 1]);
    			if (rch.query(stk[top])) dp[ stk[top - 1] ] += wt;
    			else dp[ stk[top - 1] ] += min (wt, dp[ stk[top] ]);
    			--top;
    		}
    	}
    }g2;
    
    int main () {	
    	memset (sts, 127, sizeof (sts));
    	scanf ("%d", &n);
    	for (int i = 1; i < n; ++i) {
    		ll x, y, z;
    		in, x, y, z;
    		g1.add (x, y, z), g1.add (y, x, z);
    	}
    	g1.dfs (1, 0);
    	scanf ("%d", &m);
    	while (m--) {
    		in, cnt;
    		rch.init ();
    		for (int i = 1; i <= cnt; ++i)
    			{ in, k[i]; rch.insert( k[i] ); }
    		k[++cnt] = 1;
    		sort (k + 1, k + cnt + 1, cmp);
    		g2.init ();
    		g2.build ();
    		printf ("%lld
    ", g2.dp[1]);
    	}
    	return 0;
    }
    

    Conclusion

    注意建虚树时:
    1、不能使用

    memset (h, 0, sizeof h);
    

    来初始化图,因为时间复杂度是错的。

    2、(DP) 的时候最好在建树的时候 (DP), 否则可能挂。

  • 相关阅读:
    hdu 5224 Tom and paper 水题
    2015 UESTC 搜索专题N题 韩爷的梦 hash
    2015 UESTC 搜索专题M题 Palindromic String 马拉车算法
    2015 UESTC 搜索专题K题 秋实大哥の恋爱物语 kmp
    2015 UESTC 搜索专题J题 全都是秋实大哥 kmp
    2015 UESTC 搜索专题F题 Eight Puzzle 爆搜
    2015 UESTC 搜索专题E题 吴队长征婚 爆搜
    2015 UESTC 搜索专题D题 基爷的中位数 二分
    2015 UESTC 搜索专题C题 基爷与加法等式 爆搜DFS
    2015 UESTC 搜索专题B题 邱老师降临小行星 记忆化搜索
  • 原文地址:https://www.cnblogs.com/ChiTongZ/p/11378123.html
Copyright © 2011-2022 走看看