zoukankan      html  css  js  c++  java
  • BZOJ3611: [Heoi2014]大工程

    3611: [Heoi2014]大工程

    Time Limit: 60 Sec Memory Limit: 512 MB
    Submit: 1965 Solved: 822
    [Submit][Status][Discuss]

    Description

    国家有一个大工程,要给一个非常大的交通网络里建一些新的通道。
    我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上。
    在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径。
    现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道。
    现在对于每个计划,我们想知道:
    1.这些新通道的代价和
    2.这些新通道中代价最小的是多少
    3.这些新通道中代价最大的是多少

    Input

    第一行 n 表示点数。
    接下来 n-1 行,每行两个数 a,b 表示 a 和 b 之间有一条边。
    点从 1 开始标号。 接下来一行 q 表示计划数。
    对每个计划有 2 行,第一行 k 表示这个计划选中了几个点。
    第二行用空格隔开的 k 个互不相同的数表示选了哪 k 个点。

    Output

    输出 q 行,每行三个数分别表示代价和,最小代价,最大代价。

    Sample Input

    10

    2 1

    3 2

    4 1

    5 2

    6 4

    7 5

    8 6

    9 7

    10 9

    5

    2

    5 4

    2

    10 4

    2

    5 2

    2

    6 1

    2

    6 1

    Sample Output

    3 3 3

    6 6 6

    1 1 1

    2 2 2

    2 2 2

    HINT

    n<=1000000

    q<=50000并且保证所有k之和<=2*n

    Source

    鸣谢佚名上传

    题解

    虚树。

    (sum[i])表示子树的边所能产生的权值
    (mi[i])表示子树内的点到根的最小权值
    (ma[i])表示子树内的点到根的最大权值

    #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 void swap(int &x, int &y){int 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 = 1000000 + 10;
    
    struct Edge
    {
    	int v, nxt;
    	Edge(int _v, int _nxt){v = _v, nxt = _nxt;}
    	Edge(){}
    }edge1[MAXN << 1], edge2[MAXN << 1];
    int n, q, k, t, size[MAXN], stack[MAXN * 25], top, lk[MAXN * 25], tot, dfn[MAXN], node[MAXN], head1[MAXN], cnt1, head2[MAXN], cnt2, deep[MAXN], p[30][MAXN], M, tag[MAXN];
    long long ansmi, ansma, sum[MAXN], mi[MAXN], ma[MAXN];
    inline void insert1(int a, int b)
    {
    	edge1[++ cnt1] = Edge(b, head1[a]), head1[a] = cnt1;
    	edge1[++ cnt1] = Edge(a, head1[b]), head1[b] = cnt1;
    }
    inline void insert2(int a, int b)
    {
    	edge2[++ cnt2] = Edge(b, head2[a]), head2[a] = cnt2;
    	lk[++ tot] = a;
    }
    void dfs(int x)
    {
    	dfn[x] = ++ t;
    	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, 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];
    }
    bool cmp(int a, int b)
    {
    	return dfn[a] < dfn[b];
    }
    void DP(int x)
    {
    	sum[x] = ma[x] = 0, mi[x] = tag[x] ? 0 : INF, size[x] = tag[x];
    	long long tmpmi = INF, tmpma = 0;
    	for(int pos = head2[x];pos;pos = edge2[pos].nxt)
    	{
    		int v = edge2[pos].v;
    		DP(v);
    		sum[x] += sum[v] + (long long)(deep[v] - deep[x]) * size[v] * (k - size[v]);
    		
    		long long a = mi[v] + (deep[v] - deep[x]);
    		if(mi[x] == a) tmpmi = mi[x];
    		else if(mi[x] > a) tmpmi = mi[x], mi[x] = a;
    		else tmpmi = min(tmpmi, a);
    		
    		long long b = ma[v] + (deep[v] - deep[x]);
    		if(ma[x] == b) tmpma = b;
    		else if(ma[x] < b) tmpma = ma[x], ma[x] = b;
    		else tmpma = max(tmpma, b);
    		
    		size[x] += size[v];
    	}
    	ansma = max(ansma, tmpma + ma[x]), ansmi = min(ansmi, tmpmi + mi[x]);
    }
    void build_VT()
    {
    	tot = 0, top = 0, cnt2 = 0;
    	std::sort(node + 1, node + 1 + k, cmp);
    	for(int i = 1;i <= k;++ i)
    	{
    		if(!top)
    		{
    			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;
    	ansmi = INF, ansma = 0, DP(stack[1]);
    	printf("%lld %lld %lld
    ", sum[stack[1]], ansmi, ansma);
    	for(int i = 1;i <= tot;++ i) head2[lk[i]] = 0;
    }
    int main()
    {
    	read(n);
    	for(int i = 1;i < n;++ i)
    	{
    		int tmp1, tmp2;read(tmp1), read(tmp2);
    		insert1(tmp1, tmp2);
    	}
    	read(q);dfs(1);yuchuli();
    	for(int i = 1;i <= q;++ i)
    	{
    		read(k);
    		for(int i = 1;i <= k;++ i) read(node[i]), tag[node[i]] = 1;
    		build_VT();
    		for(int i = 1;i <= k;++ i) tag[node[i]] = 0;
    	}
        return 0;
    }
    
  • 相关阅读:
    Python基础
    pip install psycopg2出现python setup.py egg_info failed with error code 1 in /tmp/pip-build-YtLeN3/psycopg2错误处理
    Python基础
    C语言基础
    benchmarks
    用 MuGo 搭建 Go Engine 在 KGS 对战
    GPU
    linux 杀掉僵尸进程 (zombie process, defunct)
    CMakeLists.txt 语法
    软件列表(按字母排序)
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/8551096.html
Copyright © 2011-2022 走看看