3611: [Heoi2014]大工程

链接

分析:

  树形dp+虚树。

  首先建立虚树,在虚树上dp。

  dp:sum[i]为i的子树中所有询问点之间的和。siz[i]为i的子树中有多少询问点,mn[i]为i的子树中询问点到根的最小距离,mx为i的子树中询问点到根的最大距离。

  具体过程见 https://www.luogu.org/blog/ShadowassIIXVIIIIV/solution-p4103

  

代码:

 #include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream> using namespace std; const int N = ;
const int INF = 1e9; int head[N<<],to[N<<],nxt[N<<];
int siz[N],deth[N],fa[N],son[N],dfn[N],bel[N],sk[N],tag[N];
int mn[N],mx[N],val[N],A[N];
long long sum[N],Sum;
int Time_index,Min,Max,TotE,top; inline int read() {
int x = ,f = ;char ch = getchar();
for (; !isdigit(ch); ch=getchar()) if(ch=='-') f=-;
for (; isdigit(ch); ch=getchar()) x=x*+ch-'';
return x * f;
}
bool cmp_dfn(const int &a,const int &b) {
return dfn[a] < dfn[b];
}
void Add_edge(int u,int v) {
++TotE; to[TotE] = v; nxt[TotE] = head[u]; head[u] = TotE;
++TotE; to[TotE] = u; nxt[TotE] = head[v]; head[v] = TotE;
}
void add_edge(int u,int v) {
++TotE; to[TotE] = v; val[TotE] = deth[v]-deth[u]; nxt[TotE] = head[u]; head[u] = TotE;
}
void dfs1(int u) {
siz[u] = ;
deth[u] = deth[fa[u]] + ; // 1的深度设为1。
for (int i=head[u]; i; i=nxt[i]) {
int v = to[i];
if (v==fa[u]) continue;
fa[v] = u;
dfs1(v);
siz[u] += siz[v];
if (!son[u] || siz[son[u]] < siz[v]) son[u] = v;
}
}
void dfs2(int u,int top) {
bel[u] = top;
dfn[u] = ++Time_index;
if (!son[u]) return ;
dfs2(son[u],top);
for (int i=head[u]; i; i=nxt[i]) {
int v = to[i];
if (v==fa[u] || v==son[u]) continue;
dfs2(v,v);
}
}
int Lca(int u,int v) {
while (bel[u] != bel[v]) {
if (deth[bel[u]] < deth[bel[v]]) swap(u,v);
u = fa[bel[u]];
}
if (deth[u] < deth[v]) return u;
return v;
}
void Insert(int p) {
int x = sk[top];
if (x==) {sk[++top] = p; return;}
int lca = Lca(x,p);
while (lca != x) {
int y = sk[--top];
if (dfn[y] < dfn[lca]) {
add_edge(lca,x);sk[++top] = lca; // !!!
break;
}
add_edge(y,x);x = sk[top];
}
sk[++top] = p;
}
void DP(int u) {
if (tag[u]) mx[u] = mn[u] = ,sum[u] = ,siz[u] = ;
else mn[u] = INF,mx[u] = -INF,sum[u] = ,siz[u] = ;
for (int i=head[u]; i; i=nxt[i]) {
int v = to[i];
DP(v);
Min = min(Min,mn[u]+mn[v]+val[i]); mn[u] = min(mn[u],mn[v]+val[i]);
Max = max(Max,mx[u]+mx[v]+val[i]); mx[u] = max(mx[u],mx[v]+val[i]);
Sum += 1ll*siz[u]*(sum[v]+val[i]*siz[v])+1ll*siz[v]*sum[u]; //!!!
sum[u] += sum[v]+val[i]*siz[v];
siz[u] += siz[v];
}
tag[u] = head[u] = ;
}
int main () { int n = read();
for (int i=; i<n; ++i) {
int u = read(),v = read();
Add_edge(u,v);
} dfs1();
dfs2(,); memset(head,,sizeof(head)); int m = read();
while (m--) {
TotE = ;top = ;sk[++top] = ; int k = read();
for (int i=; i<=k; ++i) A[i] = read(),tag[A[i]] = true;
sort(A+,A+k+,cmp_dfn); if (A[] != ) sk[++top] = A[]; // 防止1加入两边。
for (int i=; i<=k; ++i) Insert(A[i]);
while (--top) add_edge(sk[top],sk[top+]); Sum = ,Min = INF,Max = -INF;
DP();
printf("%lld %d %d\n",Sum,Min,Max);
} return ;
}

3611: [Heoi2014]大工程的更多相关文章

  1. bzoj 3611 [Heoi2014]大工程(虚树+DP)

    3611: [Heoi2014]大工程 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 408  Solved: 190[Submit][Status] ...

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

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

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

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

  4. bzoj 3611: [Heoi2014]大工程 && bzoj 2286: [Sdoi2011消耗战

    放波建虚树的模板. 大概是用一个栈维护根节点到当前关键点的一条链,把其他深度大于lca的都弹出去. 每次做完记得复原. 还有sort的时候一定要加cmp!!! bzoj 3611 #include&l ...

  5. bzoj 3611: [Heoi2014]大工程

    #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #d ...

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

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

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

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

  8. BZOJ2286 [Sdoi2011]消耗战 和 BZOJ3611 [Heoi2014]大工程

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6371  Solved: 2496[Submit][Statu ...

  9. [Bzoj3611][Heoi2014]大工程(虚树)

    3611: [Heoi2014]大工程 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 2000  Solved: 837[Submit][Status ...

随机推荐

  1. SpringBoot 很重要的一个类WebMvcConfigurerAdapter 的使用

    自定义资源映射addResourceHandlers 比如,我们想自定义静态资源映射目录的话,只需重写addResourceHandlers方法即可. @Configuration public cl ...

  2. ASP.NET 上传图片到FTP

    目录: 2.代码 3.参考资料 4.IIS环境FTP配置 5.使用虚拟目录注意Server.MapPath() 1. 项目介绍 建立FTP文件服务器与应用程序分开. 下面方法中的参数为Stream因为 ...

  3. 花3分钟了解下C/C++中的函数可变参简单实现

    1.可变参函数的原理 C/C++函数的参数是存放在栈区的,并且参数的入栈是从参数的右边开始,即最后一个参数先入栈,而第一个参数最后才入栈,所以,根据栈的后进先出性质,函数总能找到第一个参数.所以,可变 ...

  4. April 23 2017 Week 17 Sunday

    It is a characteristic of wisdom not to do desperate things. 不做孤注一掷的事情是智慧的表现. We are told that we ha ...

  5. 安装php的memcache扩展

    linux: 安装环境 RHEL 4 Php 5.2.6 所需软件 libevent-1.4.6-stable.tar.gz (http://monkey.org/~provos/libevent/) ...

  6. 分享个谷歌浏览器下的一款插件PostMan

    用作POST GET调试非常好用 先下载谷歌浏览器 然后在应用里搜索安装即可

  7. 问答 请问使用OK("raw:jpg")能返回多张图片吗

     请问使用OK("raw:jpg")能返回多张图片吗  发布于 28天前  作者 qq_3aeeb0ad  78 次浏览  复制  上一个帖子  下一个帖子  标签: 无 @At( ...

  8. halcon保存带有region的图片算子

    显示带区域的图片除了可以用dev_display挨个显示外再截图,还可以通过一个算子来实现这一功能 这个算子是:dump_window_image.(其实就是截图) 这个算子的意思是把WindowHa ...

  9. linux awk 内置函数详细介绍(实例)

    这节详细介绍awk内置函数,主要分以下3种类似:算数函数.字符串函数.其它一般函数.时间函数 一.算术函数: 以下算术函数执行与 C 语言中名称相同的子例程相同的操作: 函数名 说明 atan2( y ...

  10. IIS配置MIME类型

    有时候我们上传的视频,如果IIS上没有配置此格式是播放不了的.这个时候需要你在IIS上添加这个类型才能播放. MIME类型 ①打开你的IIS,点你的网站 ②双击 MIME类型 ③右键-->添加 ...