[COCI 2015] kamp 聚会
来源:互联网 发布:c语言if是什么意思 编辑:程序博客网 时间:2024/05/17 07:00
题目大意:n个点的一棵树上有k个关键点,每条边有一个距离,要求计算从每个点出发,用一条路径按任意顺序分别访问这k个点的路径总长度的最小值。(k<=n<=500000)
让我想艹的细节题。。。。一开始以为是sdoi2015的寻宝游戏,但我不会写那题。。。。。。
后来自已yy了一个O(n)的树形dp,但是细节TMD的多。
首先从1号点跑一遍dp。
用f1[i]表示i号节点的子树的访问关键点的最小代价,g1[i]表示访问完关键点还要回到第i号点的最小代价。然后把那些子树中不包含关键节点的儿子砍掉,可以得出
其中dis表示i号节点到他所有有用孩子的距离之和,w[i][son]表示i号点到这个孩子的距离。(即从i号点向下走遍所有有用节点再回来,然后选择一个代价最小的停下)
用_max1[i]保存一下那个f1[i]上取max的那个东西,_max2[i]存一下次大值。
然后再跑一遍dp,计算出答案。
用f2[i]表示i号节点的父亲除了i这个孩子以外的答案,g2[i]表示它的父亲除它之外的走完所有关键点再回到它父亲的最小值,f3[i]表示i号节点的最终答案,g3[i]表示最终答案还要再走回来的值。转移类比一下上面那个,什么减一减,是它最大就选次大之类的(细节太多就不写了,全写出来的一大长串看着也烦 总之就是把它父亲当做它的儿子来做就对了。。。。)
(我语死早求轻喷)
#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <cstdlib>#include <algorithm>#include <vector>#include <deque>#include <queue>#include <set>#include <map>#include <ctime>using namespace std;typedef long long LL;const int MAXN=500005; const LL INF=LL(1)<<LL(60);int n,m,tot,pos[MAXN],fst[MAXN],pre[MAXN*2],to[MAXN*2],cost[MAXN*2];LL f1[MAXN],f2[MAXN],g1[MAXN],g2[MAXN],f3[MAXN],g3[MAXN],_max1[MAXN],_max2[MAXN],fa[MAXN],fadis[MAXN]; bool vis[MAXN],flag[MAXN]; int Get(){ char ch; int v=0; bool f=false; while (!isdigit(ch=getchar())) if (ch=='-') f=true; v=ch-48; while (isdigit(ch=getchar())) v=v*10+ch-48; if (f) return -v;else return v; }void add(int x,int y,int c){ pre[++tot]=fst[x],fst[x]=tot,to[tot]=y,cost[tot]=c; pre[++tot]=fst[y],fst[y]=tot,to[tot]=x,cost[tot]=c; }LL gmax(LL a,LL b) { if (a>b) return a; return b; }void dfs1(int x){ vis[x]=true; _max1[x]=_max2[x]=g1[x]=f1[x]=0; LL dis=0; for (int i=fst[x];i;i=pre[i]) { int y=to[i]; if (!vis[y]) { fa[y]=x,fadis[y]=LL(cost[i]); dfs1(y); LL tmp=0; if (flag[y]) { flag[x]=true,g1[x]+=g1[y],dis+=LL(cost[i]); tmp=g1[y]-f1[y]+cost[i]; if (tmp>_max1[x]) _max2[x]=_max1[x],_max1[x]=tmp; else if (tmp>_max2[x]) _max2[x]=tmp; } } } if (!flag[x]) g1[x]=f1[x]=0; else g1[x]+=(dis<<1),f1[x]=g1[x]-_max1[x];}void dfs2(int x){ vis[x]=true; g2[x]=f2[x]=0; LL dis=0; int son1=0,son2=0; for (int i=fst[x];i;i=pre[i]) { int y=to[i]; if (!vis[y] && flag[y]) { if (!son1) son1=y;else son2=y; } } if (x!=1) { LL tmp=g2[fa[x]]-f2[fa[x]]+fadis[fa[x]]; if (flag[x]) { g2[x]=g3[fa[x]]-g1[x]-(fadis[x]<<1); if (_max1[fa[x]]==g1[x]-f1[x]+fadis[x]) f2[x]=g2[x]-gmax(_max2[fa[x]],tmp); else f2[x]=g2[x]-gmax(_max1[fa[x]],tmp); } else g2[x]=g3[fa[x]],f2[x]=f3[fa[x]]; g3[x]=g2[x]+g1[x]+(fadis[x]<<1),f3[x]=g3[x]-gmax(_max1[x],g2[x]-f2[x]+fadis[x]); } else g2[x]=f2[x]=0,g3[x]=g1[x],f3[x]=f1[x]; for (int i=fst[x];i;i=pre[i]) { int y=to[i]; if (!vis[y]) dfs2(y); }} int main(){ //freopen("kamp.in","r",stdin); //freopen("kamp.out","w",stdout); n=Get(),m=Get(); int x,y,c; tot=0; if (m==0) { puts("0"); return 0; } for (int i=1;i<=n-1;i++) x=Get(),y=Get(),c=Get(),add(x,y,c); for (int i=1;i<=m;i++) x=Get(),flag[x]=true; fa[1]=0,fadis[1]=0; dfs1(1); for (int i=1;i<=n;i++) vis[i]=false; dfs2(1); for (int i=1;i<=n;i++) printf("%lld\n",f3[i]); return 0; }
0 0
- [COCI 2015] kamp 聚会
- 【jzoj3919】【COCI2014/2015 Round1 KAMP】【志愿者】【树形动态规划】
- 聚会
- 聚会
- 聚会
- 聚会
- 聚会
- bzoj3743 Kamp bfs
- 3743: [Coci2015]Kamp BFS
- 3743: [Coci2015]Kamp
- [bzoj3743][Coci2015]Kamp
- 聚会聚会
- 【COCI 2015/2016 #7】PROZOR(加强版) 题解
- COCI 樱桃树
- COCI2014 COCI
- COCI 蚱蜢
- 2017.9.17 kamp 思考记录
- BZOJ 3743: [Coci2015]Kamp 树形dp
- homerHEVC代码阅读(4)——基础结构之stream_t
- 【c#】—架构函数&&析构函数
- 挖掘微信Web网页版通信的全过程
- context bounds
- JAVA的StringBuffer类
- [COCI 2015] kamp 聚会
- hpuoj 1717: 感恩节KK专场——爬楼梯 【规律题】【校赛】
- 油菜花王国——搜索
- ubuntu环境安装git
- GeekHades 非常喜欢的电影
- 《leetCode》:Search a 2D Matrix
- 分治算法之赛程安排问题
- c++11 final与override说明符
- Maven的安装以及eclipse中配置maven