zoukankan      html  css  js  c++  java
  • [洛谷P2495][SDOI2011]消耗战

    题目大意:有一棵$n(nleqslant2.5 imes10^5)$个节点的带边权的树,$m$个询问,每次询问给出$k(sumlimits_{i=1}^mk_ileqslant5 imes10^5)$个点,要求用最小的代价砍断一些边,使得$1$号点与这$k$个点都不连通,输出最小代价

    题解:先考虑一个一次$O(n)$的$DP$,可以把所有子树内没有特殊点的点先删去,令$f(i)$表示把他于他子树内所有的特殊点割断所需要的代价,即为$sumlimits_{vin son_u}min{w,f_v}$($w$为这条边边权,若$v$为关键点,$f_v=inf$)。这样的复杂度是$O(n^2)$的,不可以通过。

    可以建虚树,一般建一棵虚树的复杂度是$O(klog_2n)$的,它可以使得建出来的树中只包含最多$2k$个节点。于是就可以通过本题

    卡点:最多$2k$个点,$kleqslant n$,没有开两倍的空间

    C++ Code:

    #include <algorithm>
    #include <cctype>
    #include <cstdio>
    #include <cstring>
    namespace std {
    	struct istream {
    #define M (1 << 25 | 3)
    		char buf[M], *ch = buf - 1;
    		inline istream() {
    #ifndef ONLINE_JUDGE
    			freopen("input.txt", "r", stdin);
    #endif
    			fread(buf, 1, M, stdin);
    		}
    		inline istream& operator >> (int &x) {
    			while (isspace(*++ch));
    			for (x = *ch & 15; isdigit(*++ch); ) x = x * 10 + (*ch & 15);
    			return *this;
    		}
    #undef M
    	} cin;
    	struct ostream {
    #define M (1 << 25 | 3)
    		char buf[M], *ch = buf - 1;
    		inline ostream& operator << (int x) {
    			if (!x) {*++ch = '0'; return *this;}
    			static int S[11], *top; top = S;
    			while (x) {*++top = x % 10 ^ 48; x /= 10;}
    			for (; top != S; --top) *++ch = *top;
    			return *this;
    		}
    		inline ostream& operator << (long long x) {
    			if (!x) {*++ch = '0'; return *this;}
    			static int S[20], *top; top = S;
    			while (x) {*++top = x % 10 ^ 48; x /= 10;}
    			for (; top != S; --top) *++ch = *top;
    			return *this;
    		}
    		inline ostream& operator << (const char x) {*++ch = x; return *this;}
    		inline ~ostream() {
    #ifndef ONLINE_JUDGE
    			freopen("output.txt", "w", stdout);
    #endif
    			fwrite(buf, 1, ch - buf + 1, stdout);
    		}
    #undef M
    	} cout;
    }
    
    #define maxn 250010
    
    int head[maxn], cnt;
    struct Edge {
    	int to, nxt, w;
    } e[maxn << 1];
    inline void addedge(int a, int b, int c) {
    	e[++cnt] = (Edge) {b, head[a], c}; head[a] = cnt;
    }
    
    int in[maxn], out[maxn], idx, dep[maxn];
    namespace Tree {
    #define M 17
    	int fa[maxn][M + 1], Min[maxn][M + 1];
    	void dfs(int u) {
    		in[u] = ++idx;
    		for (int i = 1; i <= M; i++) {
    			fa[u][i] = fa[fa[u][i - 1]][i - 1];
    			Min[u][i] = std::min(Min[u][i - 1], Min[fa[u][i - 1]][i - 1]);
    		}
    		for (int i = head[u]; i; i = e[i].nxt) {
    			int v = e[i].to;
    			if (v != *fa[u]) {
    				*fa[v] = u;
    				*Min[v] = e[i].w;
    				dep[v] = dep[u] + 1;
    				dfs(v);
    			}
    		}
    		out[u] = idx;
    	}
    	inline int LCA(int x, int y) {
    		if (dep[x] < dep[y]) std::swap(x, y);
    		for (int i = dep[x] - dep[y]; i; i &= i - 1) x = fa[x][__builtin_ctz(i)];
    		if (x == y) return x;
    		for (int i = M; ~i; i--) if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
    		return *fa[x];
    	}
    	const int inf = 0x3f3f3f3f;
    	inline int query(int x, int k) {
    		int res = inf;
    		for (int i = k; i; i &= i - 1) {
    			res = std::min(res, Min[x][__builtin_ctz(i)]);
    			x = fa[x][__builtin_ctz(i)];
    		}
    		return res;
    	}
    #undef M
    }
    
    int n, m;
    namespace Work {
    	const long long inf = 0x3f3f3f3f3f3f3f3f;
    	inline bool cmp(int a, int b) {return in[a] < in[b];}
    
    	int k;
    	int list[maxn << 1], S[maxn], top;
    	long long f[maxn];
    	bool imp[maxn];
    
    	void dfs(int u) {
    		f[u] = 0;
    		for (int i = head[u]; i; i = e[i].nxt) {
    			int v = e[i].to;
    			dfs(v);
    			f[u] += std::min(f[v], static_cast<long long> (e[i].w));
    		}
    		if (imp[u]) f[u] = inf, imp[u] = false;
    		head[u] = 0;
    	}
    
    	void solve() {
    		cnt = 0;
    		std::cin >> k;
    		for (int i = 0; i < k; i++) {
    			std::cin >> list[i];
    			imp[list[i]] = true;
    		}
    
    		std::sort(list, list + k, cmp);
    		int tot = k;
    		for (int i = 0; i < k - 1; i++) list[tot++] = Tree::LCA(list[i], list[i + 1]);
    		list[tot++] = 1;
    		tot = (std::sort(list, list + tot, cmp), std::unique(list, list + tot) - list);
    		top = 0;
    		for (int I = 0, i = *list; I < tot; I++, i = list[I]) {
    			while (top && out[S[top]] < in[i]) top--;
    			if (top) addedge(S[top], i, Tree::query(i, dep[i] - dep[S[top]]));
    			S[++top] = i;
    		}
    
    		dfs(1);
    		std::cout << f[1] << '
    ';
    	}
    }
    
    int main() {
    	std::cin >> n;
    	for (int i = 1, u, v, w; i < n; i++) {
    		std::cin >> u >> v >> w;
    		addedge(u, v, w);
    		addedge(v, u, w);
    	}
    	Tree::dfs(1);
    	std::cin >> m;
    	memset(head, 0, sizeof head);
    	while (m --> 0) Work::solve();
    	return 0;
    }
    

      

  • 相关阅读:
    C语言_航模社第四节
    C语言_航模社第三节
    C语言交换两个变量的值
    C语言表达分段函数
    c语言_2017.10.22
    stm32_配置GPIO点亮led灯
    prteus8安装教程
    安装keil_5步骤
    nginx配置实现https的配置文件方法
    TortoiseGit 代码版本回退及返回
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/10184109.html
Copyright © 2011-2022 走看看