题目链接

要求的和、最大值、最小值好像都可以通过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. 【矩阵】RQ/QR 分解

    Multiple View Geometry in Computer Vision A.4.1.1 (page 579) 将一个 3x3 矩阵 $ A $ 进行 RQ 分解是将其分解成为一个上三角阵 ...

  2. Python——脚本(calculator)

    <Python基础教程>(第二版) P123 书中原代码如下: class Calculator: def calculator(self,expression): self.value ...

  3. JavaScript 金额、数字、千分位、千分位、保留几位小数、舍入舍去、支持负数

    JavaScript 金额.数字 千分位格式化.保留指定位数小数.支持四舍五入.进一法.去尾法 字段说明: number:需要处理的数字: decimals:保留几位小数,默认两位,可不传: dec_ ...

  4. 使用netcat的正向 / 反向shell

    reverse shell bind shell reverse shell描述图: 在此示例中,目标使用端口4444反向连接攻击主机.-e选项将Bash shell发回攻击主机.请注意,我们也可以在 ...

  5. C#里partial关键字的作用

    1. 什么是局部类型?C# 2.0 引入了局部类型的概念.局部类型允许我们将一个类.结构或接口分成几个部分,分别实现在几个不同的.cs文件中.局部类型适用于以下情况: (1) 类型特别大,不宜放在一个 ...

  6. python configparser配置文件解析器

    一.Configparser 此模块提供实现基本配置语言的ConfigParser类,该语言提供类似于Microsoft Windows INI文件中的结构.我们经常会在一些软件安装目录下看到.ini ...

  7. 关于Unity启动时间过长(启动黑屏时间长)的问题!!! 牛逼... 思路不错...

    http://blog.csdn.net/u012169685/article/details/52068809

  8. kafka集群及监控部署

    1. kafka的定义 kafka是一个分布式消息系统,由linkedin使用scala编写,用作LinkedIn的活动流(Activity Stream)和运营数据处理管道(Pipeline)的基础 ...

  9. Bugfree3.0.4 Linux环境安装指南

    一. 安装apache服务器 1. 检查apache服务器是否安装 service httpd status 2. 如提示未被识别的服务,则表明组件未安装,需手动安装 yum install http ...

  10. MyEclipse开发工具,当选中一个单词时,其他相同的单词会被高亮显示(选中/标记)

    1.步骤: Window-->Preferences-->Java-->Editor-->Mark Occurremces下的 Mark Occurremces of the ...