题目链接

  我貌似发现这类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. Linux赋予普通用户root权限

    本文以新建用户admin来举例,请自行替换自己需要的用户 方法一: vi编辑 /etc/sudoers 文件,找到 root    ALL=(ALL)     ALL,在下面添加一行,如下所示: ## ...

  2. POJ1286 Necklace of Beads(Polya定理)

    Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 9359   Accepted: 3862 Description Beads ...

  3. Java连接数据库的一个问题

    问题描述: 利用HTML+servlet+MySQL写一个简单的登录注册案例,抛出了异常No suitable driver found for jdbc 解决方法 将mysql-connector- ...

  4. 基于mybatis设计简单信息管理系统---jsp页面

    1.在设计编辑界面的时候需要有一个下拉的列表页,想要他指定到指定的值: <select id="categoryId" name="categoryId" ...

  5. Spring MVC 接收前端参数的方式

    方式一: 普通方式接收 1 @RequestMapping("/index") 2 public String getUserName(String username) { 3 S ...

  6. 基于centos7实现的nfs

    NFS NFS(Network FileSystem,网络文件系统),最早由Sun公司所发展出来的,主要是通过网络让不同的主机.不同的操作系统,可以彼此分享个别档案,因此我们也可以简单把NFS看成是一 ...

  7. Salt-ssh 自动安装salt-minion

    作用:为了不手动去安装一台一台去salt-minion,并进重复的配置 一.环境 系统环境: #cat /etc/redhat-release CentOS Linux release 7.4.170 ...

  8. Windows手工创建服务方法

    需要将程序设置成Windows服务的情况,可以利用一下windows自带的sc命令来创建服务. 该命令的基本用法如下:打开cmd命令, 输入如下信息:1 创建服务:sc create SecServe ...

  9. C语言数组篇(一)一维数组

       0.  数组的两种表现形式         一种是常见的a[10];         //初学者常用         另一种是用指针表示的数组.   //实际工程使用.常用于参数传递       ...

  10. tomcat7 配置 https安全访问

    在apache-tomcat-7.0.33-windows-x64.zip配置https,结果在配置SSL时遇到一些问题 1.用JDK自带的keytool来生成私有密钥和自签发的证书,如下: keyt ...