zoukankan      html  css  js  c++  java
  • BZOJ2286: [Sdoi2011]消耗战

    2286: [Sdoi2011]消耗战

    Time Limit: 20 Sec Memory Limit: 512 MB
    Submit: 4833 Solved: 1788
    [Submit][Status][Discuss]

    Description

    在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。
    侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到1号岛屿上)。不过侦查部门还发现了这台机器只能够使用m次,所以我们只需要把每次任务完成即可。

    Input

    第一行一个整数n,代表岛屿数量。

    接下来n-1行,每行三个整数u,v,w,代表u号岛屿和v号岛屿由一条代价为c的桥梁直接相连,保证1<=u,v<=n且1<=c<=100000。

    第n+1行,一个整数m,代表敌方机器能使用的次数。

    接下来m行,每行一个整数ki,代表第i次后,有ki个岛屿资源丰富,接下来k个整数h1,h2,…hk,表示资源丰富岛屿的编号。

    Output

    输出有m行,分别代表每次任务的最小代价。

    Sample Input

    10

    1 5 13

    1 9 6

    2 1 19

    2 4 8

    2 3 91

    5 6 8

    7 5 4

    7 8 31

    10 7 9

    3

    2 10 6

    4 5 7 8 3

    3 9 4 6

    Sample Output

    12

    32

    22

    HINT

    对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1

    题解

    (dp[i])表示以(i)为根的子树,使黑点不与(i)连通的最小割边权值和。
    转移有

    [i is black : dp[i] = mi[i] ]

    [i is white : dp[i] = min(mi[i], sum dp[son_i]) ]

    其中(mi[i])表示点i到根的路径上的最小边权

    题目有(sum_{i=1}^{k}k_i leq 10^5)
    所以用虚树即可,可以证明点数是(nlog_n)级别的

    如何建虚树

    注意不要每次都清空图,否则复杂度退化为nm会T的
    记录下那些head需要被清0,同时不要全部开longlong,longlong真心慢,会T

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <cmath>
    inline long long max(long long a, long long b){return a > b ? a : b;}
    inline long long min(long long a, long long b){return a < b ? a : b;}
    inline long long abs(long long x){return x < 0 ? -x : x;}
    inline void swap(int &x, int &y){long long tmp = x;x = y;y = tmp;}
    
    template <class T>
    inline void read(T &x)
    {
        x = 0;char ch = getchar(), c = ch;
        while(ch < '0' || ch > '9') c = ch, ch = getchar();
        while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
        if(c == '-') x = -x;
    }
    const long long INF = 0x3f3f3f3f3f3f3f3f;
    const int MAXN = 250000 + 10;
    
    //Tree
    struct Edge
    {
    	int u,v,nxt;
    	long long w;
    	Edge(int _u, int _v, long long _w, int _nxt){u = _u, v = _v, w = _w, nxt = _nxt;}
    	Edge(){}
    }edge1[MAXN << 1], edge2[MAXN << 1];
    int head1[MAXN << 1], head2[MAXN << 1], cnt1, cnt2, deep[MAXN], p[30][MAXN], dfn[MAXN], tt, M, n, m;
    long long mi[MAXN];
    int node[MAXN], tot, stack[MAXN * 20], top, tag[MAXN], re[MAXN], pt;
    inline void insert1(int a, int b, long long c)
    {
    	edge1[++ cnt1] = Edge(a, b, c, head1[a]), head1[a] = cnt1;
    	edge1[++ cnt1] = Edge(b, a, c, head1[b]), head1[b] = cnt1;
    }
    inline void insert2(int a, int b, long long c = 0)
    {
    	edge2[++ cnt2] = Edge(a, b, c, head2[a]), head2[a] = cnt2;
    	re[++ pt] = a;
    }
    void dfs(int x)
    {
    	dfn[x] = ++ tt;
    	for(int pos = head1[x];pos;pos = edge1[pos].nxt)
    	{
    		int v = edge1[pos].v;
    		if(v == p[0][x]) continue;
    		deep[v] = deep[x] + 1, mi[v] = min(mi[x], edge1[pos].w), p[0][v] = x;
    		dfs(v);
    	}
    }
    void yuchuli()
    {
    	while((1 << M) <= n) ++ M;-- M;
    	for(int i = 1;i <= M;++ i)
    		for(int j = 1;j <= n;++ j)
    			p[i][j] = p[i - 1][p[i - 1][j]];
    } 
    int LCA(int va, int vb)
    {
    	if(deep[va] < deep[vb]) swap(va, vb);
    	for(int i = M;i >= 0;-- i)
    		if(deep[va] - deep[vb] >= (1 << i))
    			va = p[i][va];
    	if(va == vb) return va;
    	for(int i = M;i >= 0;-- i)
    		if(p[i][va] != p[i][vb])
    			va = p[i][va], vb = p[i][vb];
    	return p[0][va];
    }
    
    //Virtual Tree
    bool cmp(int a, int b)
    {
    	return dfn[a] < dfn[b];
    }
    
    void build_VT()
    {
    	cnt2 = pt = top = 0;
    	std::sort(node + 1, node + 1 + tot, cmp);
    	for(int i = 1;i <= tot;++ i)
    	{
    		if(top == 0)
    		{
    			stack[++ top] = node[i];
    			continue;
    		}
    		int lca = LCA(stack[top], node[i]);
    		while(deep[lca] < deep[stack[top]])
    		{
    			if(deep[lca] >= deep[stack[top - 1]])
    			{
    				insert2(lca, stack[top]);
    				if(stack[-- top] != lca) stack[++ top] = lca;
    				break;
    			}
    			insert2(stack[top - 1], stack[top]), -- top;
    		}
    		stack[++ top] = node[i];
    	}
    	while(top > 1) insert2(stack[top - 1], stack[top]), -- top;
    }
    
    //DP
    long long dp[MAXN];
    void DP(int x, int pre)
    {
    	long long sum = 0;
    	for(int pos = head2[x];pos;pos = edge2[pos].nxt)
    	{
    		int v = edge2[pos].v;
    		DP(v, x);
    		sum += dp[v];
    	}
    	if(tag[x] || !sum) dp[x] = mi[x];
    	else dp[x] = min(mi[x], sum);
    } 
    
    int main()
    {
    	memset(mi, 0x3f, sizeof(mi)), memset(dp, 0x3f, sizeof(dp));
    	read(n);
    	for(int i = 1;i < n;++ i)
    	{
    		int tmp1, tmp2;
    		long long tmp3;
    		read(tmp1), read(tmp2), read(tmp3);
    		insert1(tmp1, tmp2, tmp3);
    	}
    	dfs(1);yuchuli();
    	read(m);
    	for(int i = 1;i <= m;++ i)
    	{
    		read(tot);
    		for(int j = 1;j <= tot;++ j)
    			read(node[j]), tag[node[j]] = 1;
    		build_VT(), DP(stack[1], -1);
    		for(int j = 1;j <= tot;++ j)
    			tag[node[j]] = 0;
    		for(int i = 1;i <= pt;++ i) 
    			head2[re[i]] = 0;
    		printf("%lld
    ", dp[stack[1]]);	
    	}
        return 0;
    }
    
  • 相关阅读:
    windows下使用C#获取特定进程网络流量
    .NET设计模式(9):桥接模式(Bridge Pattern)(转)
    .NET设计模式(8):适配器模式(Adapter Pattern)(转)
    .NET设计模式(7):创建型模式专题总结(Creational Pattern)(转)
    .NET设计模式(6):原型模式(Prototype Pattern)(转)
    .NET设计模式(5):工厂方法模式(Factory Method)(转)
    .NET设计模式(4):建造者模式(Builder Pattern)(转)
    .NET设计模式(3):抽象工厂模式(Abstract Factory)(转)
    单件模式(Singleton Pattern)(转)
    PowerDesigner(九)-模型文档编辑器(生成项目文档)(转)
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/8543703.html
Copyright © 2011-2022 走看看