题目链接

要求的和、最大值、最小值好像都可以通过O(n)的树形DP做,总询问点数<=2n。

于是建虚树就可以了。具体DP见DP()函数,维护三个值sum[],mx[],mn[]。

sum[]要开longlong!。。

//108172kb	2564ms(又是Rank4...)
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 1000000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e6+5,M=N<<1,INF=5e8; int n,Q,K,A[N],Enum,H[N],nxt[M],to[M],val[M],dep[N],tp[N],top,sk[N],dfn[N],Index,fa[N],son[N],sz[N],mn[N],mx[N],Min,Max;
LL Sum,sum[N];
bool tag[N];
char IN[MAXIN],*SS=IN,*TT=IN; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline bool cmp_dfn(const int &a,const int &b){
return dfn[a]<dfn[b];
}
inline void Add_direct(int u,int v){
to[++Enum]=v, nxt[Enum]=H[u], val[Enum]=dep[v]-dep[u], H[u]=Enum;
}
inline void AddEdge(int u,int v){
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
void DFS1(int x)
{
int mx=0; sz[x]=1;
for(int v,i=H[x]; i; i=nxt[i])
if((v=to[i])!=fa[x])
{
fa[v]=x, dep[v]=dep[x]+1, DFS1(v), sz[x]+=sz[v];
if(mx<sz[v]) mx=sz[v], son[x]=v;
}
}
void DFS2(int x,int _tp)
{
dfn[x]=++Index, tp[x]=_tp;
if(son[x])
{
DFS2(son[x],_tp);
for(int i=H[x]; i; i=nxt[i])
if(to[i]!=fa[x]&&to[i]!=son[x]) DFS2(to[i],to[i]);
}
}
int LCA(int u,int v)
{
while(tp[u]!=tp[v]) dep[tp[u]]>dep[tp[v]]?u=fa[tp[u]]:v=fa[tp[v]];
return dep[u]>dep[v]?v:u;
}
void Insert(int p)
{
if(top==1) {sk[++top]=p; return;}
int lca=LCA(sk[top],p);
// if(lca==sk[top]) {sk[++top]=p; return;}
while(dfn[sk[top-1]]>=dfn[lca]) Add_direct(sk[top],sk[top--]);
if(lca!=sk[top] && dfn[sk[top-1]]<dfn[lca]) Add_direct(lca,sk[top]), sk[top]=lca;
sk[++top]=p;
}
void DP(int x)
{
sum[x]=0;
if(tag[x]) mn[x]=0, mx[x]=0/*可以以此为一端点*/, sz[x]=1;
else mn[x]=INF, mx[x]=-INF, sz[x]=0;
for(int v,i=H[x]; i; i=nxt[i])
{
DP(v=to[i]);
Min=std::min(Min, mn[x]+mn[v]+val[i]), mn[x]=std::min(mn[x], mn[v]+val[i]);
Max=std::max(Max, mx[x]+mx[v]+val[i]), mx[x]=std::max(mx[x], mx[v]+val[i]);
Sum+=1ll*sz[x]*(sum[v]+val[i]*sz[v])+1ll*sz[v]*sum[x];//之前的此时会被统计sz[v]次,v子树被统计sz[x]次 //long long!
sum[x]+=sum[v]+val[i]*sz[v], sz[x]+=sz[v];
}
tag[x]=H[x]=0;
} int main()
{
n=read();
for(int i=1; i<n; ++i) AddEdge(read(),read());
DFS1(1), DFS2(1,1), Enum=0, memset(H,0,sizeof H);// memset(sz,0,sizeof sz);
Q=read();
while(Q--)
{
K=read();
for(int i=1; i<=K; ++i) tag[A[i]=read()]=1;
std::sort(A+1,A+1+K,cmp_dfn);
sk[top=1]=1;
if(A[1]==1) for(int i=2; i<=K; ++i) Insert(A[i]);//以1为根,注意不要加1两次。。
else for(int i=1; i<=K; ++i) Insert(A[i]);
while(--top) Add_direct(sk[top],sk[top+1]);//! Sum=0, Min=INF, Max=-INF, DP(1);
printf("%lld %d %d\n",Sum,Min,Max);
Enum=0;// for(int i=1; i<=K; ++i) H[A[i]]=0;
}
return 0;
}

BZOJ.3611.[HEOI2014]大工程(虚树 树形DP)的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. bzoj 3611: [Heoi2014]大工程

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

随机推荐

  1. Ubuntu下 git 服务器的搭建【转】

    转自:http://www.open-open.com/lib/view/open1391477731082.html 搭建git服务器的4个步骤 1   配置服务器前的准备工作 首先ubuntu系统 ...

  2. C/C++杂记:NULL与0的区别、nullptr的来历

    某些时候,我们需要将指针赋值为空指针,以防止野指针.   有人喜欢使用NULL作为空指针常量使用,例如:int* p = NULL;. 也有人直接使用0值作为空指针常量,例如:int* p = 0;. ...

  3. Django-模板语言和过滤器

    Django模板语言 首先模板只是一个文本文件,它可以生成任何基于文本的格式(HTML.XML.CSS等),模板中包含变量,在模板被渲染的时候替换为最终的值,以及控制模板逻辑的标签. 变量使用{{ 变 ...

  4. gc overhead limit exceeded内存问题

    gc overhead limit exceeded 当出现这种问题的时候一般有两种思路 一.修改idea或者eclipse中的配置文件,将内存调到1024即可 二.在代码中通过system.gc 手 ...

  5. css-css背景

    CSS 允许应用纯色作为背景,也允许使用背景图像创建相当复杂的效果 一:背景色background-color 属性 p {background-color: gray;} 二:背景图像 backgr ...

  6. 【Android开发日记】之入门篇(五)——Android四大组件之Service

    这几天忙着驾校考试,连电脑都碰不到了,今天总算告一段落了~~Service作为Android的服务组件,默默地在后台为整个程序服务,辅助应用与系统中的其他组件或系统服务进行沟通.它跟Activity的 ...

  7. java基础40 可变参数、自动装箱和自动拆箱

    一.可变参数 可变参数是jdk1.5新特性 1.1.可变参数的格式 数据类型...变量名 // 数据类型...变量名public static void sum(int...arr){ } 1.2.可 ...

  8. 洛谷P3203弹飞绵羊

    传送门啦 非常神奇的分块大法. 每块分 √N 个元素 , 预处理出来:对于每个点,记录两个量:一个是它要弹几次才能出它所在的这个块,另外一个是它弹出这个块后到哪个点. 查询操作:一块一块跳过去 单次复 ...

  9. 使用T-SQL导入多个文件数据到SQL Server中

    在我们的工作中,经常需要连续输入多个文件的数据到SQL Server的表中,有时需要从相同或者不同的目录中,同时将文件中的数据倒入.在这篇文章中,我们将讨论如何同时把一个目录中的文件的数据倒入到SQL ...

  10. ObjectInputStream与ObjectOutputStream

    雇员类 package io; import java.io.Serializable; @SuppressWarnings("serial") public class Emp ...