BZOJ 3611

明明在BZOJ上是$6s$的时限,怎么到Luogu上就变成$4s$了……

按照套路建出虚树,点之间的距离可以变成边权表示在虚树上,然后考虑如何树形$dp$。

最大值和最小值应当比较简单,类似于树形$dp$求树的直径的方法,设$f_x$表示$x$的子树中的关键点到$x$的最远距离,$g_x$则表示最近距离。

对于每一个$x$,如果$x$是一个关键点,则有$f_x = g_x = 0$,否则$f_x = -inf, g_x = inf$。

对于$x$的每一个儿子$y$,先用$f_x + f_y + val(x, y)$和$g_x + g_y + val(x, y)$更新$ans$,再用$f_x + val(x, y)$和$g_x + val(x, y)$更新$f_x$和$g_x$。

考虑一下怎么求所有边权的总和,我们发现一条边被计算的次数等于把这条边断开所分割成的两个联通块中的关键点的数量的乘积,那么它对答案的贡献就是这条边的边权乘上这个乘积。

其实除了根结点,所有的点都唯一对应了一条入边,我们先预处理一个点$x$,子树中关键点的数目$siz_x$,那么每一条入边$inEdge$的贡献就是$val(inEdge) * siz_x * (siz_{root} - x)$。

一开始犯了一个错误,就是不能把$1$强制作根,类似于点分治的时候需要减掉的贡献,这样会导致最长的路径变长,我们只要找到第一个入栈的点为$root$即可。

我的代码在$Luogu$上需要一发$O2$,感觉写欧拉序求$lca$会更好。

时间复杂度$O(nlogn)$。

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll; const int N = 1e6 + ;
const int Lg = ;
const ll inf = 1LL << ; int n, qn, tot = , head[N], fa[N][Lg], dep[N];
int rt, top = , sta[N * ], dfsc = , in[N], out[N], a[N * ], siz[N];
ll sum, maxD, minD, f[N], g[N];
bool vis[N], flag[N]; struct Edge {
int to, nxt, val;
} e[N << ]; inline void add(int from, int to, int val = ) {
e[++tot].to = to;
e[tot].val = val;
e[tot].nxt = head[from];
head[from] = tot;
} namespace IOread {
const int L = << ; char buffer[L], *S, *T; inline char Getchar() {
if(S == T) {
T = (S = buffer) + fread(buffer, , L, stdin);
if(S == T) return EOF;
}
return *S++;
} template <class T>
inline void read(T &X) {
char ch; T op = ;
for(ch = Getchar(); ch > '' || ch < ''; ch = Getchar())
if(ch == '-') op = -;
for(X = ; ch >= '' && ch <= ''; ch = Getchar())
X = (X << ) + (X << ) + ch - '';
X *= op;
} } using namespace IOread; bool cmp(int x, int y) {
int dfx = x > ? in[x] : out[-x];
int dfy = y > ? in[y] : out[-y];
return dfx < dfy;
} inline void swap(int &x, int &y) {
int t = x; x = y; y = t;
} template <typename T>
inline void chkMax(T &x, T y) {
if(y > x) x = y;
} template <typename T>
inline void chkMin(T &x, T y) {
if(y < x) x = y;
} void dfs(int x, int fat, int depth) {
in[x] = ++dfsc, fa[x][] = fat, dep[x] = depth;
for(int i = ; i <= ; i++)
fa[x][i] = fa[fa[x][i - ]][i - ];
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs(y, x, depth + );
}
out[x] = ++dfsc;
} inline int getLca(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
for(int i = ; i >= ; i--)
if(dep[fa[x][i]] >= dep[y])
x = fa[x][i];
if(x == y) return x;
for(int i = ; i >= ; i--)
if(fa[x][i] != fa[y][i])
x = fa[x][i], y = fa[y][i];
return fa[x][];
} inline int getDis(int x, int y) {
int z = getLca(x, y);
return dep[x] + dep[y] - * dep[z];
} void dfs1(int x, int fat) {
if(flag[x]) ++siz[x], g[x] = f[x] = ;
else g[x] = inf, f[x] = -inf;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs1(y, x);
siz[x] += siz[y]; chkMax(maxD, f[x] + f[y] + e[i].val);
chkMax(f[x], f[y] + e[i].val); chkMin(minD, g[x] + g[y] + e[i].val);
chkMin(g[x], g[y] + e[i].val);
}
} void dfs2(int x, int fat, int inEdge) {
if(fat != )
sum += 1LL * e[inEdge].val * (siz[rt] - siz[x]) * siz[x];
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs2(y, x, i);
}
} void solve() {
int K, cnt; read(K);
for(int i = ; i <= K; i++) {
read(a[i]);
if(!vis[a[i]]) {
vis[a[i]] = ;
flag[a[i]] = ;
}
} cnt = K;
sort(a + , a + + K, cmp);
for(int i = ; i < cnt; i++) {
int now = getLca(a[i], a[i + ]);
if(!vis[now]) {
vis[now] = ;
a[++cnt] = now;
}
} for(int cur = cnt, i = ; i <= cur; i++)
a[++cnt] = -a[i];
// if(!vis[1]) a[++cnt] = 1, a[++cnt] = -1, vis[1] = 1;
sort(a + , a + + cnt, cmp); /* for(int i = 1; i <= cnt; i++)
printf("%d ", a[i]);
printf("\n"); */ top = rt = ;
for(int i = ; i <= cnt; i++) {
if(a[i] > ) {
sta[++top] = a[i];
if(!rt) rt = a[i];
} else {
int x = sta[top--], y = sta[top];
if(y) {
int nowDis = getDis(x, y);
add(x, y, nowDis), add(y, x, nowDis);
}
}
} sum = 0LL, minD = inf, maxD = -inf;
dfs1(rt, ), dfs2(rt, , ); printf("%lld %lld %lld\n", sum, minD, maxD); tot = ;
for(int i = ; i <= cnt; i++)
if(a[i] > ) {
vis[a[i]] = flag[a[i]] = ;
head[a[i]] = siz[a[i]] = ;
// f[a[i]] = -inf, g[a[i]] = inf;
}
} int main() {
read(n);
for(int x, y, i = ; i < n; i++) {
read(x), read(y);
add(x, y), add(y, x);
}
dfs(, , ); tot = ; memset(head, , sizeof(head));
for(read(qn); qn--; ) solve(); return ;
}

Luogu 4103 [HEOI2014]大工程的更多相关文章

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

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

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

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

  3. 洛谷4103 HEOI2014大工程(虚树+dp)

    又是一道虚树好题啊 我们建出来虚树,然后考虑dp过程,我们分别令\(sum[x],mndis[x],mxdis[x],size[x]\)为子树内的路径长度和,最短链,最长链,子树内关键点个数. 对于一 ...

  4. 3611: [Heoi2014]大工程

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

  5. [BZOJ3611][Heoi2014]大工程

    [BZOJ3611][Heoi2014]大工程 试题描述 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道.  我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上.  在 ...

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

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

  7. 【LG4103】[HEOI2014]大工程

    [LG4103][HEOI2014]大工程 题面 洛谷 题解 先建虚树,下面所有讨论均是在虚树上的. 对于第一问:直接统计所有树边对答案的贡献即可. 对于第\(2,3\)问:记\(f[x]\)表示在\ ...

  8. P4103 [HEOI2014]大工程

    题目 P4103 [HEOI2014]大工程 化简题目:在树上选定\(k\)个点,求两两路径和,最大的一组路径,最小的一组路径 做法 关键点不多,建个虚树跑一边就好了 \(sum_i\)为\(i\)子 ...

  9. BZOJ2286 [Sdoi2011]消耗战 和 BZOJ3611 [Heoi2014]大工程

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6371  Solved: 2496[Submit][Statu ...

随机推荐

  1. Mac 系统安装redis服务

    1.首先去http://www.redis.io/下载最新的redis文件,现在最新的是redis-2.8.19 2.进行解压缩 tar -zxvf redis-2.8.19.tar.gz 3.移动重 ...

  2. 3.4 常用的两种 layer 层 3.7 字体与文本

    3.4 常用的两种 layer 层  //在cocos2d-x中,经常使用到的两种 layer 层 : CCLayer 和 CCLayerColor //CCLayer 的创建 CCLayer* la ...

  3. windows下matplotlib的安装

    在上一篇中我想用matplotlib,无奈一直装不上,就在卸了又装装了又卸,反反复复之后,终于装好了. 初学python,首先就装了numpy,倒也没有多复杂,有需要的朋友可以直接http://sou ...

  4. angular的$q,defer,promise

    $q是Angular的一种内置服务,它可以使你异步地执行函数,并且当函数执行完成时它允许你使用函数的返回值(或异常). 官网:http://docs.angularjs.cn/api/ng/servi ...

  5. BZOJ3809:Gty的二逼妹子序列

    浅谈莫队:https://www.cnblogs.com/AKMer/p/10374756.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php?i ...

  6. LTE-V2X车联网无线通信技术发展

    2017年9月7日,国家制造强国建设领导小组车联网产业发展专项委员会第一次全体会议在北京召开.会议要求“要加大关键产品研发攻关力度,完善测试验证.技术评价.质量认证等公共服务平台,促进LTE-V2X车 ...

  7. 机器学习:评价分类结果(ROC 曲线)

    一.基础理解 1)定义 ROC(Receiver Operation Characteristic Curve) 定义:描述 TPR 和 FPR 之间的关系: 功能:应用于比较两个模型的优劣: 模型不 ...

  8. 四川第七届 C Censor (字符串哈希)

    Censor frog is now a editor to censor so-called sensitive words (敏感词). She has a long text pp. Her j ...

  9. redux使用教程详细介绍

    本文介绍redux的使用 安装 cnpm install redux --save cnpm install react-redux --save cnpm install redux-devtool ...

  10. docker 安装mysql 使用navicat访问 解决

    1. 下载Mysql的Docker镜像: 2. 运行镜像,设置root账号初始密码(123456),映射本地宿主机端口3306到Docker端口3306.测试过程没有挂载本地数据盘: 3. 查看已运行 ...