• 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), 否则可能挂。

  • 相关阅读:
    Linux下tty/pty/pts/ptmx详解
    ubuntu 12 或更高版本 下安装和配置 xrdp 远程登陆
    ubuntu+apache2+php5+mysql5.0的安装
    Ubuntu SSH 服务安装配置和使用
    ubuntu 12.10 进入命令行界面 (字符界面)
    ubuntu 下使用 cron 和 crontab
    Ubuntu用命令行发邮件mutt,报警发短信通知
    Ubuntu 安装 proftpd,并添加虚拟用户
    绝对有效的 ubuntu 12.xx 下 apache2 + svn 安装和配置方法
    添加android系统通知
  • 原文地址:https://www.cnblogs.com/ChiTongZ/p/11378123.html
Copyright © 2020-2023  润新知