3611: [Heoi2014]大工程


Time Limit: 60 Sec  Memory Limit: 512 MB
Submit: 2000  Solved: 837
[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



Sample Output



HINT


n<=1000000

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

Source


题解:


其实数据范围第二句话就摆明是虚树了。。

然后看看这道题要我们做啥,求虚树关键点间最长链,最短链,两两距离和。。

关于距离和,我们只用在dfs时考虑一下当前点,和它儿子结点的边会有多少点对经过就行。

设总关键点为k,一个点x子树所包含关键点数量为sz[x]

当然就是(k - sz[son]) * sz[son]次啦。设每个点到它父亲边被经过次数为cnti

距离就是 dep[son] - dep[now]。设为这个距离为wi

答案就是

就这样我们把第一个询问做出来了。

第二第三询问树上最长最短链,noip--难度。但是有树上有关键点之间的lca啊,当它为链的起点或终点时答案会增大。

然后仔细一想我们只有在当前点为关键点时才会计算单条链贡献。

因为虚点都是关键点间lca所以不会出现虚点为叶子结点,这样就保证起点和终点不会是虚点了。

然后就简单虚树上dp了。

AC代码:


# include <iostream>
# include <cstdio>
# include <cstring>
# include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e6 + ;
const int inf = 0x3f3f3f3f;
int sz[N],hson[N],top[N],dep[N],que[N],k,a[N],g[N];LL f[N];
int head[N],dt,tot,fa[N],id[N],n,m,mx[N],mi[N],ans1,ans2;
struct Edge{
int to,nex;
}edge[N << ];
void AddEdge(int u,int v)
{
if(u == v)return;
edge[++dt] = (Edge){v,head[u]};
head[u] = dt;
}
void dfs(int u)
{
sz[u] = ;
for(int i = head[u];i;i = edge[i].nex)
{
if(sz[edge[i].to])continue;
dep[edge[i].to] = dep[u] + ;
fa[edge[i].to] = u;
dfs(edge[i].to);
sz[u] += sz[edge[i].to];
if(sz[hson[u]] < sz[edge[i].to])hson[u] = edge[i].to;
}
}
void dfs(int u,int tp)
{
top[u] = tp;id[u] = ++tot;
if(hson[u])dfs(hson[u],tp);
for(int i = head[u];i;i = edge[i].nex)
if(!id[edge[i].to])dfs(edge[i].to,edge[i].to);
head[u] = ;
}
int lca(int u,int v)
{
while(top[u] != top[v])
{
if(dep[top[u]] < dep[top[v]])swap(u,v);
u = fa[top[u]];
}
return dep[u] < dep[v] ? u : v;
}
bool cmp(int x,int y){return id[x] < id[y];}
void dp(int u)
{
sz[u] = g[u];mx[u] = ;mi[u] = inf;f[u] = ;
for(int i = head[u];i;i = edge[i].nex)
{
int w = dep[edge[i].to] - dep[u];
dp(edge[i].to);sz[u] += sz[edge[i].to];
ans1 = min(ans1,mi[u] + mi[edge[i].to] + w);mi[u] = min(mi[u],mi[edge[i].to] + w);
ans2 = max(ans2,mx[u] + mx[edge[i].to] + w);mx[u] = max(mx[u],mx[edge[i].to] + w);
f[u] += f[edge[i].to] + 1LL * sz[edge[i].to] * (k - sz[edge[i].to]) * w;
}
if(g[u])ans1 = min(ans1,mi[u]),ans2 = max(ans2,mx[u]),mi[u] = ;
head[u] = g[u] = ;
}
void solve()
{
scanf("%d",&k);int top,gr;ans1 = inf;top = dt = ans2 = ;ans1 = inf;
for(int i = ;i <= k;i++)scanf("%d",&a[i]),g[a[i]] = ;
sort(a + ,a + k + ,cmp);
for(int i = ;i <= k;i++)
{
if(!top){que[++top] = a[i];continue;}
gr = lca(que[top],a[i]);
while(id[gr] < id[que[top]])
{
if(id[gr] >= id[que[top - ]])
{
AddEdge(gr,que[top]);
if(que[--top] != gr)que[++top] = gr;
break;
}
AddEdge(que[top - ],que[top]);top--;
}
if(que[top] != a[i])que[++top] = a[i];
}
top--;
while(top)AddEdge(que[top],que[top + ]),top--;
dp(que[]);
printf("%lld %d %d\n",f[que[]],ans1,ans2);
}
int main()
{
scanf("%d",&n);int x,y;
for(int i = ;i < n;i++)
{
scanf("%d %d",&x,&y);
AddEdge(x,y);AddEdge(y,x);
}
dfs();dfs(,);
scanf("%d",&m);
while(m--)solve();
}

[Bzoj3611][Heoi2014]大工程(虚树)的更多相关文章

  1. bzoj 3611: [Heoi2014]大工程 虚树

    题目: 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 ...

  2. luogu P4103 [HEOI2014]大工程 虚树 + 树形 DP

    Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道.  我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上.  在 2 个国家 a,b 之间建一条新通 ...

  3. 洛谷P4103 [HEOI2014]大工程(虚树 树形dp)

    题意 链接 Sol 虚树. 首先建出虚树,然后直接树形dp就行了. 最大最小值直接维护子树内到该节点的最大值,然后合并两棵子树的时候更新一下答案. 任意两点的路径和可以考虑每条边两边的贡献,\(d[x ...

  4. bzoj 3611(洛谷 4103) [Heoi2014]大工程——虚树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3611 https://www.luogu.org/problemnew/show/P4103 ...

  5. BZOJ.3611.[HEOI2014]大工程(虚树 树形DP)

    题目链接 要求的和.最大值.最小值好像都可以通过O(n)的树形DP做,总询问点数<=2n. 于是建虚树就可以了.具体DP见DP()函数,维护三个值sum[],mx[],mn[]. sum[]要开 ...

  6. BZOJ 3611 [Heoi2014]大工程 ——虚树

    虚树第二题.... 同BZOJ2286 #include <map> #include <cmath> #include <queue> #include < ...

  7. bzoj 3611[Heoi2014]大工程 虚树+dp

    题意: 给一棵树 每次选 k 个关键点,然后在它们两两之间 新建 C(k,2)条 新通道. 求: 1.这些新通道的代价和 2.这些新通道中代价最小的是多少 3.这些新通道中代价最大的是多少 分析:较常 ...

  8. [BZOJ3611][Heoi2014]大工程

    [BZOJ3611][Heoi2014]大工程 试题描述 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道.  我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上.  在 ...

  9. [BZOJ3611][Heoi2014]大工程(虚树上DP)

    3611: [Heoi2014]大工程 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 2464  Solved: 1104[Submit][Statu ...

随机推荐

  1. Summary of 2016 International Trusted Computing and Cloud Security Summit

    1)      Welcome Remarks 2)      The advancement of Cloud Computing and Tursted Computing national st ...

  2. PMP项目管理学习笔记(10)——范围管理之收集需求

    一个星期没看书,没记录笔记,没能坚持下来,感觉好罪过.现在我要重新上路! 收集需求 收集需求就是与项目的所有干系人坐在一起,得出他们的需求是什么,这就是收集需求过程中要做的事情.你的项目要想成功,你就 ...

  3. c# sqlserver连接字符串

    odbc: string cnnstring = @"Driver={SQL Server Native Client 11.0};Initial Catalog = sxquadb;ser ...

  4. PHP memcache扩展安装 for Windows

    一.下载并安装memcached服务器端软件    1.下载memcached软件 32位下载地址: memcached-win32-1.4.4-14.zip(直接下载),memcached-win3 ...

  5. 原创Couldn't read packet: Connection reset by peer 错误排查思路(推荐)

    作为一个运维 不是你懂多少知识才是你的价值 你有幸能遇到多少错误才是你的最大的价值 知识 你有我有大家有  错误我有你没有 这便是我的价值 我遇到一个错误 蛮难遇到的一个错误 所以想分享给大家 下面我 ...

  6. 管道命令和xargs的区别(经典解释) 自己的总结

    1. 简介 之所以能用到这个命令,关键是由于很多命令不支 持|管道来传递参数,而日常工作中有有这个必要, 所以就有了xargs命令,例如:find /sbin -perm +700 |ls -l 这个 ...

  7. easyUI-datagrid属性设置display:none,表头不显示

    <div class="box1"> <div class="dg1Box" style="margin-top:15px; mar ...

  8. select onchange事件的使用

    <select name="expireDay" id="expireDay" class="form-control" onchan ...

  9. java面试微信交流群-欢迎你的加入

    Java后端技术专注Java相关技术:SSM.Spring全家桶.微服务.MySQL.MyCat.集群.分布式.中间件.Linux.网络.多线程,偶尔讲点运维Jenkins.Nexus.Docker. ...

  10. Python旅途——文件操作

    Python--文件操作 1.理解文件操作 可能有的时候有人会在想为什么要对文件进行操作,无论对于文件还是网络之间的交互,我们都是建立在数据之上的,如果我们没有数据,那么很多的事情也就不能够成立,比如 ...