构建出虚树然后DP统计答案

自己写的DP太傻QAQ,各种WA

膜了一发PoPoQQQ大爷的DP方法

mxdis,mndis分别表示到当前点近期和最远的被选出来的点的距离

mx,mn分别表示在以当前点为根的情况下距离最远的两点的距离和距离近期的两点的距离。

sum表示在以当前点为根的子树中,全部关键的到当前点的距离之和

c数组表示以当前点为根的子树中。关键点的个数

然后我用了个时间戳来标记关键点

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#define inf 0x7FFFFFFF
#define ll long long
#define N 1000005
using namespace std;
int sc()
{
int i=0,f=1; char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
return i*f;
}
ll mx[N],mn[N],mn_dis[N],mx_dis[N],c[N],sum[N],ans;
int Head[N],Nxt[N],Lst[N];
int a[N],st[N],tim[N];
int size[N],deep[N],fa[N],S[N],top[N];
int head[N],lst[N<<1],nxt[N<<1],v[N<<1];
int n,tot,cnt,Tot,TI;
void Insert(int x,int y)
{
Lst[++Tot]=y;Nxt[Tot]=Head[x];Head[x]=Tot;
}
void insert(int x,int y)
{
lst[++tot]=y;nxt[tot]=head[x];head[x]=tot;
lst[++tot]=x;nxt[tot]=head[y];head[y]=tot;
}
void dfs(int x,int f)
{
size[x]=1;
for(int i=head[x];i;i=nxt[i])
if(lst[i]!=f)
{
deep[lst[i]]=deep[x]+1;
fa[lst[i]]=x;
dfs(lst[i],x);
size[x]+=size[lst[i]];
}
}
void _dfs(int x,int htp)
{
int k=0;top[x]=htp;S[x]=++cnt;
for(int i=head[x];i;i=nxt[i])
if(lst[i]!=fa[x]&&size[lst[i]]>size[k])k=lst[i];
if(!k)return;_dfs(k,htp);
for(int i=head[x];i;i=nxt[i])
if(lst[i]!=k&&lst[i]!=fa[x])
_dfs(lst[i],lst[i]);
}
int Lca(int x,int y)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])swap(x,y);
x=fa[top[x]];
}
return deep[x]<deep[y]? x:y;
}
bool cmp(int x,int y){return S[x]<S[y];}
ll dis(int x,int y)
{
return deep[x]+deep[y]-2*deep[Lca(x,y)];
}
void dp(int x)
{
c[x]=tim[x]==TI;sum[x]=0;
mx_dis[x]=tim[x]==TI?0:-inf;
mn_dis[x]=tim[x]==TI?0:inf;
mn[x]=inf;mx[x]=-inf;
for(int i=Head[x];i;i=Nxt[i])
{
ll d=dis(Lst[i],x); dp(Lst[i]);
ans+=sum[x]*c[Lst[i]]+(sum[Lst[i]]+c[Lst[i]]*d)*c[x];
c[x]+=c[Lst[i]];
sum[x]+=sum[Lst[i]]+c[Lst[i]]*d;
mx[x]=max(mx[x],max(mx[Lst[i]],mx_dis[Lst[i]]+d+mx_dis[x]));
mn[x]=min(mn[x],min(mn[Lst[i]],mn_dis[Lst[i]]+d+mn_dis[x]));
mx_dis[x]=max(mx_dis[x],mx_dis[Lst[i]]+d);
mn_dis[x]=min(mn_dis[x],mn_dis[Lst[i]]+d);
}
Head[x]=0;
} void solve()
{
int n=sc(),top=0;Tot=0;TI++;
for(int i=1;i<=n;i++)
tim[a[i]=sc()]=TI;
sort(a+1,a+n+1,cmp);
if(a[1]!=1)st[++top]=1;
for(int i=1;i<=n;i++)
{
int t=a[i],f=0;
while(top)
{
f=Lca(st[top],t);
if(top>1&&deep[f]<deep[st[top-1]]) Insert(st[top-1],st[top]),top--;
else if(deep[f]<deep[st[top]]){Insert(f,st[top]);top--;break;}
else break;
}
if(st[top]!=f&&f)st[++top]=f;
st[++top]=t;
}
while(--top)Insert(st[top],st[top+1]);
ans=0;dp(1);
printf("%lld %lld %lld\n",ans,mn[1],mx[1]);
}
int main()
{
n=sc();
for(int i=1;i<n;i++)
{
int x=sc(),y=sc();
insert(x,y);
}
dfs(1,0);_dfs(1,1);
for(int i=1,m=sc();i<=m;i++)
solve();
return 0;
}

3611: [Heoi2014]大project|树形DP|虚树的更多相关文章

  1. BZOJ3611:[HEOI2014]大工程(树形DP,虚树)

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

  2. [BZOJ3611] [Heoi2014]大工程(DP + 虚树)

    传送门 $dp[i][0]$表示节点i到子树中的所有点的距离之和 $dp[i][1]$表示节点i到子树中最近距离的点的距离 $dp[i][2]$表示节点i到子树中最远距离的点的距离 建好虚树后dp即可 ...

  3. 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分

    树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...

  4. 【CF809E】Surprise me! 树形DP 虚树 数学

    题目大意 给你一棵\(n\)个点的树,每个点有权值\(a_i\),\(a\)为一个排列,求 \[ \frac{1}{n(n-1)}\sum_{i=1}^n\sum_{j=1}^n \varphi(a_ ...

  5. CF613D:Kingdom and its Cities(树形DP,虚树)

    Description 一个王国有n座城市,城市之间由n-1条道路相连,形成一个树结构,国王决定将一些城市设为重要城市. 这个国家有的时候会遭受外敌入侵,重要城市由于加强了防护,一定不会被占领.而非重 ...

  6. BZOJ2286:[SDOI2011]消耗战(树形DP,虚树)

    Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军 ...

  7. 3611: [Heoi2014]大工程

    3611: [Heoi2014]大工程 链接 分析: 树形dp+虚树. 首先建立虚树,在虚树上dp. dp:sum[i]为i的子树中所有询问点之间的和.siz[i]为i的子树中有多少询问点,mn[i] ...

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

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

  9. HDU 4514 - 湫湫系列故事——设计风景线 - [并查集判无向图环][树形DP求树的直径]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4514 Time Limit: 6000/3000 MS (Java/Others) Memory Li ...

随机推荐

  1. C#判断字符串的是否是汉字

    //第一种方法:正则表达式 private bool IsChinese(string Text) { ; i < Text.Length; i++) { if (Regex.IsMatch(T ...

  2. C#实现缩放字体

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  3. 便利的初始化view以及设置tag值

    便利的初始化view以及设置tag值 效果 源码 https://github.com/YouXianMing/iOS-Project-Examples 中的 SetRect // // Access ...

  4. Xcode下修改plist文件

    plist文件在Mac OS下的重要性,如同Windows下的注册表文件.而很多场景下面,我们需要修改plist文件来实现一些"自动化"操作   Mac OS本身提供了一个工具:P ...

  5. Library drmframework_jni not found

    http://piotrbuda.eu/2012/06/trying-to-solve-error-491-in-play-store-on-android-emulator.html http:// ...

  6. mysql group by 报错异常解决

    mysql报错及其解决方式 1.在使用group by 查询一张表的数据的时候:select date,time,max(delaytime) as delaytime,sum(delaynum) a ...

  7. .Net Core HTML解析利器之HtmlAgilityPack

    一 .HtmlAgilityPack简介 这是一个敏捷的HTML解析器,它构建了一个读/写DOM,并支持简单的XPATH或XSLT(实际上,你实际上并不了解XPATH和XSLT来使用它,不必担心).它 ...

  8. 深入理解多线程(五)—— Java虚拟机的锁优化技术

    本文是<深入理解多线程>的第五篇文章,前面几篇文章中我们从synchronized的实现原理开始,一直介绍到了Monitor的实现原理. 前情提要 通过前面几篇文章,我们已经知道: 1.同 ...

  9. 最近遇到了 timer1sec 定时调用的函数,出现了 时间久了,就不是每秒一次了,可能会慢的情况。如何解决呢?

    我想可以在timer1sec 调用四个线程,让四个线程来执行 具体代码,而不是在timer1sec一个线程 直接执行.这样,每个线程 不超过4s,那么没秒都会被调用到. 需要使用到的技术是 semap ...

  10. c++流缓冲学习---rdbuf()

    我们使用STL编程的时候有时候会想到把一个流对象指向的内容用另一个流对象来输出,比如想把一个文件的内容输出到显示器上,我们可以用简单的两行代码就可以完成: ifstream infile(" ...