3743: [Coci2015]Kamp

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 484  Solved: 229
[Submit][Status][Discuss]

Description

一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的。
有K个人(分布在K个不同的点)要集中到一个点举行聚会。
聚会结束后需要一辆车从举行聚会的这点出发,把这K个人分别送回去。
请你回答,对于i=1~n,如果在第i个点举行聚会,司机最少需要多少时间把K个人都送回家。

Input

第一行两个数,n,K。
接下来n-1行,每行三个数,x,y,z表示x到y之间有一条需要花费z时间的边。
接下来K行,每行一个数,表示K个人的分布。

Output

输出n个数,第i行的数表示:如果在第i个点举行聚会,司机需要的最少时间。

Sample Input

7 2
1 2 4
1 3 1
2 5 1
2 4 2
4 7 3
4 6 2
3
7

Sample Output

11
15
10
13
16
15
10

HINT

【数据规模】
K <= N <= 500000
1 <= x,y <= N, 1 <= z <= 1000000
分析:本来想用状压dp的,但是n这么大,怎么压的下来。其实这道题有一个结论:如果我们把要送达的点建立一棵树,那么答案就是这棵树上的边权和*2+i到这棵树的最短距离(假设为j点)-j到树上最远一点的距离.其实也很好想为什么,要遍历树上的点最少肯定要每条边都走两次,i点要到这棵树上肯定要走最短距离,我们到一个点后就不回起点了,那么肯定终点在最远的那个点上.
      那么想要做出这道题就要用到4个dfs.首先求出每个点在不在树上,然后求出i到树上最近的点和最短距离,接下来求出每个点到它的叶子节点的最长距离和次长距离,最后求出每个点的最长距离.
      第一步和第二步很好理解,关键是最后两步,我们求最长距离为什么还要求每个点到它的叶子节点的最长距离和次长距离呢?其实这有点像树链剖分,我们把树链分为最长链和次长链,位于最长链的儿子成为重儿子,重儿子的最远距离点肯定在它的子节点中或者次长链中,这就包含了最长链和次长链两种情况,没有其它情况了,轻儿子的最远距离也肯定在它的子节点或者最长链中,所以我们先求出父节点到子节点的最远距离和次远距离,然后利用父节点更新子节点,很难想到啊.
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; const int maxn = ; int n, k,head[maxn],to[maxn * ],nextt[maxn * ],w[maxn * ],tot = ,ner[maxn],son[maxn];
long long mind[maxn],maxd[maxn],secd[maxn],d[maxn],sum;
bool flag[maxn],vis[maxn]; void add(int x, int y, int z)
{
w[tot] = z;
to[tot] = y;
nextt[tot] = head[x];
head[x] = tot++;
} bool dfs1(int x) //找树
{
vis[x] = ;
for (int i = head[x]; i; i = nextt[i])
{
int v = to[i];
if (!vis[v])
{
if (dfs1(v))
{
flag[x] = ;
sum += w[i];
}
}
}
return flag[x];
} void dfs2(int x) //找最短距离
{
vis[x] = ;
if (flag[x])
ner[x] = x;
for (int i = head[x]; i; i = nextt[i])
{
int v = to[i];
if (!vis[v] && !flag[v])
{
mind[v] = mind[x] + w[i];
ner[v] = ner[x];
}
if (!vis[v])
dfs2(v);
}
} long long dfs3(int x) //最长距离+次长距离
{
vis[x] = ;
for (int i = head[x]; i; i = nextt[i])
{
int v = to[i];
if (!vis[v] && flag[v])
{
long long t = dfs3(v) + w[i];
if (t > maxd[x])
{
secd[x] = maxd[x];
maxd[x] = t;
son[x] = v;
}
else
if (t > secd[x])
secd[x] = t;
}
}
return maxd[x];
} void dfs4(int x, long long lmax) //最后的更新
{
vis[x] = ;
for (int i = head[x]; i; i = nextt[i])
{
int v = to[i];
d[x] = max(lmax, maxd[x]);
if (flag[v] && !vis[v])
{
if (v == son[x])
dfs4(v, max(lmax, secd[x]) + w[i]);
else
dfs4(v, max(lmax, maxd[x]) + w[i]);
}
}
} int main()
{
memset(flag, false, sizeof(flag));
scanf("%d%d", &n, &k);
for (int i = ; i < n; i++)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
add(y, x, z);
}
int t;
for (int i = ; i <= k; i++)
{
scanf("%d", &t);
flag[t] = ;
}
dfs1(t);
memset(vis, , sizeof(vis));
dfs2(t);
memset(vis, , sizeof(vis));
dfs3(t);
memset(vis, , sizeof(vis));
dfs4(t, );
for (int i = ; i <= n; i++)
printf("%lld\n", sum * + mind[i] - d[ner[i]]); return ;
}

bzoj3743 [Coci2015]Kamp 常州模拟赛d6t2的更多相关文章

  1. 常州模拟赛d4t1 立方体

    题目描述 立方体有 6 个面,每个面上有一只奶牛,每只奶牛都有一些干草.为了训练奶牛的合作精神,它 们在玩一个游戏,每轮:所有奶牛将自己的干草分成 4 等份,分给相邻的 4 个面上的奶牛. 游戏开始, ...

  2. [Bzoj3743][Coci2015] Kamp【换根Dp】

    Online Judge:Bzoj3743 Label:换根Dp,维护最长/次长链 题目描述 一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的. 有K个人(分布在K个不同的 ...

  3. bzoj3743: [Coci2015]Kamp

    首先树dp求出一个点的答案 然后再一遍dfs换根(是叫做换根吗.. 详见代码 #include <iostream> #include <cstdio> #include &l ...

  4. 2018.09.28 bzoj3743: [Coci2015]Kamp(树形dp)

    传送门 这是一道很有意思的题. 我们把所有的关键点都提出来,当成一棵有边权的虚树. 然后发现虚树上除最后不回到虚根的那条路径外外每条边都会被走两遍. 显然要让答案最优,不走的路径应该在虚树的直径上,于 ...

  5. 常州模拟赛d7t3 水管

    分析:第一问还是很好做的,关键是怎么做第二问.我们可以每次删掉最小生成树上的一条边,然后再求一次最小生成树,看边权和大小和原来的是不是一样的,不过这个做法效率很低. 考虑Kruskal算法的原理,每次 ...

  6. 常州模拟赛d6t3 噪音

    FJ有M个牛棚,编号1至M,刚开始所有牛棚都是空的.FJ有N头牛,编号1至N,这N头牛按照编号从小到大依次排队走进牛棚,每一天只有一头奶牛走进牛棚.第i头奶牛选择走进第p[i]个牛棚.由于奶牛是群体动 ...

  7. 常州模拟赛d5t2 mogician

    分析:一个暴力的思想是枚举g,然后枚举每个数ai,看能不能符合要求,这样复杂度是O(nA)的,直接T掉了.也没什么其他的办法了,在暴力的基础上优化一下,优化的关键是要如何快速统计出不满足要求的数的个数 ...

  8. 常州模拟赛d5t1 journalist

    分析:出题人丧心病狂卡spfa......只能用dijkstar+堆优化. 主要的难点是字典序的处理上,一个想法是在做最短路的时候处理,边松弛边记录,比个大小记录最佳答案.具体的思路大概和最短路计数差 ...

  9. 常州模拟赛d4t3 字符串划分

    题目描述 给你一串由小写字母组成的字符串,希望你把它划分成一些小段,使得每一小段字符串中的字母 都不相同,并且希望分的段数尽量少. 然后,把这些小段按字典序排序后输出,中间由一个空格分隔. 例如:字符 ...

随机推荐

  1. Flask应用运行流程

    当我们运行项目后,Flask内部都经历了什么 1.app.run()启动项目,ctrl点进源码 app.py: 1)执行了run_simple() 2)注意第三个参数,这里是Flask实例化的对象,在 ...

  2. Sqlserver 2012 Always on技术

    使用了Sqlserver 2012 Always on技术后,假如采用的配置是默认配置,会出现Primary server CPU很高的情况发生,比如默认配置如下: 需要自定义来解决这个问题. 我们先 ...

  3. POJ 1741 Tree (树的分治,树的重心)

    题意:给一棵树,n个节点,给定一个数k,求任意满足dist(a,b)<=k的点对的数量. 思路: 这道题的思路比较简单,但是细节很多. 此题可以用分治法,如何分治? (1)如果path(a,b) ...

  4. 将从SQL2008 r2里备份的数据库还原到SQL2008中

    从标题可以看出这是未解决上一篇遗留问题写的,现在我也不知道这个可不可以成功,方法似乎查到了一种,具体怎样还不清楚:而且,我想说的是“我踩雷了”. 这篇的主角是“Database Publishing ...

  5. 为什么字符串String是不可变字符串&&"".equals(str)与str.equals("")的区别

    为什么字符串String是不可变字符串 实际上String类的实现是char类型的数组 虽然说源码中设置的是private final char[] value; final关键词表示不可变动 但是只 ...

  6. Hdoj—1789

    //大意理解 先排序 最早交的里面选最大值 扫描完了加没写的 排序后 应该是早交的和扣分多的在前 用结构体吧/*#include<stdio.h>#include<stdio.h&g ...

  7. SQL与脚本语言

    SQL是人类与数据库沟通的语言https://zhidao.baidu.com/question/413397944.html我个人认为SQL是一种专门对数据库进行操作的特殊的脚本语言.因为SQL语句 ...

  8. C#中Lock关键字的使用

    C# 中的 Lock 语句通过隐式使用 Monitor 来提供同步功能.lock 关键字在块的开始处调用 Enter,而在块的结尾处调用 Exit. 通常,应避免锁定 public 类型,否则实例将超 ...

  9. CSS 隐藏 visibility 属性

    定义和用法 visibility 属性规定元素是否可见. 提示:即使不可见的元素也会占据页面上的空间.请使用 "display" 属性来创建不占据页面空间的不可见元素. 说明 这个 ...

  10. 条款39:明智而审慎地使用private继承(use private inheritance judiciously)

    NOTE: 1.private 继承意味 is-implemented-in-terms-of(根据某物实现出).它通常比复合(composition)的级别低.但是当derivated class需 ...