题目链接

  我貌似发现这类DP就是先别管什么虚树……把树形DP搞出来套上虚树板子就好了

  这个树形DP就是设sum为答案,sumd为子树内所有点的深度和(当然指的是被询问的点),maxi指子树内最深的点的深度,mini同理

  然后考虑我们dfs到x,它的儿子已经遍历到一半,新加进来一个儿子to

  显然$sum[x]+=sum[to]+(sumd[x]-deep[x]*size[x])*size[to]+sumd[to]-deep[x]*size[to]$

  $sumd+=sum[to]$

  $maxi[x]=max(maxi[x],maxi[to])$

  只要注意这类方程的先后顺序即可。

  另外注意输出的先后顺序。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#define maxn 1020020
using namespace std;
inline long long read(){
long long num=,f=;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-;
ch=getchar();
}
while(isdigit(ch)){
num=num*+ch-'';
ch=getchar();
}
return num*f;
} long long sum[maxn],maxi[maxn],mini[maxn];
long long sumd[maxn];
long long ansa[maxn],ansb[maxn];
long long size[maxn]; long long dfn[maxn];
long long deep[maxn];
long long q[maxn];
long long stack[maxn],top;
long long s[maxn][];
bool vis[maxn];
long long ID; struct Pic{
struct Edge{
long long next,to;
}edge[maxn*];
long long head[maxn],num;
inline void add(long long from,long long to){
edge[++num]=(Edge){head[from],to};
head[from]=num;
}
void pre(long long x,long long fa){
dfn[x]=++ID; deep[x]=deep[fa]+;
for(long long i=head[x];i;i=edge[i].next){
long long to=edge[i].to;
if(to==fa) continue;
s[to][]=x;
pre(to,x);
}
return;
}
void dele(int x,int fa){
for(int i=head[x];i;i=edge[i].next){
int to=edge[i].to;
if(to==fa) continue;
dele(to,x);
}
head[x]=;
}
void dfs(long long x,long long fa){
sum[x]=maxi[x]=sumd[x]=size[x]=; ansa[x]=; ansb[x]=0x7fffffff;
mini[x]=0x7fffffff;
//printf("%lld %lld %lld %d>>>\n",sum[x],x);
for(long long i=head[x];i;i=edge[i].next){
long long to=edge[i].to;
if(to==fa) continue;
//printf("%d %d\n",x,to);
dfs(to,x);
if(maxi[x]) ansa[x]=max(ansa[x],maxi[x]+maxi[to]-*deep[x]);
if(mini[x]!=0x7fffffff) ansb[x]=min(ansb[x],mini[x]+mini[to]-*deep[x]);
maxi[x]=max(maxi[x],maxi[to]);
mini[x]=min(mini[x],mini[to]);
sum[x]+=sum[to];
//printf("%lld? %d????????\n",sum[x],x);
if(sumd[x]) sum[x]+=(sumd[x]-deep[x]*size[x])*size[to]+(sumd[to]-deep[x]*size[to])*size[x];
//printf("%lld %lld %d %d!!!!!!\n",sum[x],sumd[x],x,to);
size[x]+=size[to];
sumd[x]+=sumd[to];
ansa[x]=max(ansa[x],ansa[to]);
ansb[x]=min(ansb[x],ansb[to]);
}
if(vis[x]){
if(sumd[x]) sum[x]+=sumd[x]-(deep[x]*size[x]);
sumd[x]+=deep[x];
if(maxi[x]) ansa[x]=max(ansa[x],maxi[x]-deep[x]);
if(mini[x]!=0x7fffffff) ansb[x]=min(ansb[x],mini[x]-deep[x]);
maxi[x]=max(maxi[x],deep[x]);
mini[x]=min(mini[x],deep[x]);
size[x]++;
}
//printf("%lld %d\n",sum[x],x);
return;
}
}old,vir; bool cmp(long long a,long long b){ return dfn[a]<dfn[b]; } inline long long LCA(long long x,long long y){
if(deep[x]<deep[y]) swap(x,y);
long long f=deep[x]-deep[y];
for(long long i=;(<<i)<=f;++i)
if((<<i)&f) x=s[x][i];
if(x==y) return x;
for(long long i=;i>=;--i){
if(s[x][i]==s[y][i]) continue;
x=s[x][i];y=s[y][i];
}
return s[x][];
} int main(){
long long n=read();
for(long long i=;i<n;++i){
long long x=read(),y=read();
old.add(x,y); old.add(y,x);
}
old.pre(,);
for(long long j=;j<;++j)
for(long long i=;i<=n;++i) s[i][j]=s[s[i][j-]][j-];
long long m=read();
while(m--){
vir.num=top=;
long long e=read();
//printf("%d>>\n",e);
for(long long i=;i<=e;++i){
q[i]=read();
vis[q[i]]=;
// printf("%d>>>",dfn[q[i]]);
}
//printf("\n");
sort(q+,q+e+,cmp);
for(long long i=;i<=e;++i){
if(top==){
stack[++top]=q[i];
continue;
}
long long lca=LCA(q[i],stack[top]);
while(dfn[lca]<dfn[stack[top]]){
if(dfn[lca]>=dfn[stack[top-]]){
vir.add(lca,stack[top]);
if(stack[--top]!=lca) stack[++top]=lca;
break;
}
vir.add(stack[top-],stack[top]);
top--;
}
stack[++top]=q[i];
}
while(top>){
vir.add(stack[top-],stack[top]);
top--;
}
vir.dfs(stack[],stack[]);
printf("%lld %lld %lld\n",sum[stack[]],ansb[stack[]],ansa[stack[]]);
for(long long i=;i<=e;++i) vis[q[i]]=;
vir.dele(stack[],stack[]);
}
return ;
}

【Luogu】P4103大工程(虚树DP)的更多相关文章

  1. [HEOI2014][bzoj3611] 大工程 [虚树+dp]

    题面: 传送门 思路: 又是一道虚树入门级的题目,但是这道题的实际难点在于dp 首先,这道题是可以点分治做的,而且因为6s时限随便浪,所以写点分治也不是不可以 但是,dp因为$O\left(n\rig ...

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

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

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

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

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

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

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

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

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

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

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

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

  8. 【HEOI2014】大工程<虚树>

    虚树 我们每天都用心思索着,这究竟是为了什么呢?我想我也不知道,只是觉得如果人不思考问题就很无聊. 我觉得虚树不是什么数据结构,就是一种技巧或者工具.它能把树中\(k\)个关键点以\(O(klogk) ...

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

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

  10. bzoj 3572世界树 虚树+dp

    题目大意: 给一棵树,每次给出一些关键点,对于树上每个点,被离它最近的关键点(距离相同被标号最小的)控制 求每个关键点控制多少个点 分析: 虚树+dp dp过程如下: 第一次dp,递归求出每个点子树中 ...

随机推荐

  1. XML 对xml文件的crud的增加 create操作 增加元素 增加属性

    把创建的节点挂到上一节点的最后 找到参考节点,使用insertBefore方法进行插入位置 xml添加属性使用setAttribute方法

  2. c++ 11 线程池的简单封装

    #include <condition_variable> #include <queue> #include <thread> #include <vect ...

  3. iOS 多线程 之 GCD(大中枢派发)(二)

    本文接着上一篇讲.主要讲:dispatch_source. dispatch_source主要用户监听事件,可以监听如下事件 DISPATCH_SOURCE_TYPE_DATA_ADD DISPATC ...

  4. 《Linux就该这么学》,刘小伙实在人,给打个广告

    本书是由全国多名红帽架构师(RHCA)基于最新Linux系统共同编写的高质量Linux技术自学教程,极其适合用于Linux技术入门教程或讲课辅助教材,目前是国内最值得去读的Linux教材,也是最有价值 ...

  5. Cluster - HA -keepalived

    学习须知 VRRP:https://www.cnblogs.com/aftree/p/9376427.html 需求 集群中,对后端RealServer的状态做检测,实现自动化问题检测和问题自动处理机 ...

  6. PHP 面向对象 static 和 self 的区别

    一.前言 php是世界上最好的语言 php从面向过程走到现在成熟的面向对象体系, 在php面向对象中,静态变量的调用我们可以用这两个self::method和 static::method, 但是很多 ...

  7. python 函数复习

    # 函数 # 可读性强 复用性强 # def 函数名(): # 函数体 #return 返回值 # 所有的函数 只定义不调用就一定不执行 #先定义后调用 #函数名() #不接收返回值 #返回值 = 函 ...

  8. Robolectric

    今天学习了单元测试框架,Robolectric.初步感觉,可能我测试的少,没有感觉Robolectric能有多大的帮助.虽然可以帮助创建activity.可以模拟点击事件.可是有什么呢. 好吧,讲下使 ...

  9. JWT应用

    调试器库简介问一件T恤! 精心制作 JSON Web令牌简介 新:免费获得JWT手册并深入学习JWT! 什么是JSON Web Token? JSON Web Token(JWT)是一个开放标准(RF ...

  10. 让菜鸡讲一讲费用流(EK)

    让我再讲一个故事吧. 又有一些小精灵要准备从银月城(S)迁徙到Nibel山(T). 这两个地方之间的道路构成了一个网络. 每个道路都有它自己的容量,这决定了每天有多少小精灵可以同时从这儿通过. 和上一 ...