题意

分析

考场做法

一眼看出是支持换根的树形dp。

用\(f(x,0/1)\)表示x及其子树中,从x出发,不一定/一定回到x的最大收益。

然后子树很好做。

换根的时候,我先计算后还原,需要考虑很多,调了很久。

后来知道可以用up,down状态转移,会好写一些,但要考虑得跟我先前打的差不多。

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#include<cassert>
#define rg register
#define il inline
#define co const
#pragma GCC optimize ("O0")
using namespace std;
template<class T> il T read()
{
T data=0;
int w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
data=10*data+ch-'0',ch=getchar();
return data*w;
}
template<class T> il T read(T&x)
{
return x=read<T>();
}
typedef long long ll;
const int INF=0x7fffffff; co int MAXN=3e5+7; struct Edge
{
int nx,to,w;
}E[MAXN<<1];
int head[MAXN],ecnt; il void addedge(rg int x,rg int y,rg int w)
{
E[++ecnt].to=y,E[ecnt].w=w;
E[ecnt].nx=head[x],head[x]=ecnt;
} int fa[MAXN],fw[MAXN];
int val[MAXN]; ll f[MAXN][2];
int maxv[MAXN],secv[MAXN]; il ll take(rg int y)
{
return max(0LL,f[y][0]-fw[y]);
} il ll fetch(rg int y)
{
return max(0LL,f[y][1]-2*fw[y]);
} il ll calc(rg int y)
{
return take(y)-fetch(y);
} il void dfs1(rg int x,rg int fath)
{
fa[x]=fath;
f[x][1]=val[x];
for(rg int i=head[x];i;i=E[i].nx)
{
rg int y=E[i].to,w=E[i].w;
if(y==fath)
{
fw[x]=w;
continue;
}
dfs1(y,x);
f[x][1]+=fetch(y);
}
f[x][0]=f[x][1];
for(rg int i=head[x];i;i=E[i].nx)
{
rg int y=E[i].to;
if(y==fath)
continue;
if(calc(y)>calc(secv[x]))
{
secv[x]=y;
if(calc(secv[x])>calc(maxv[x]))
swap(secv[x],maxv[x]);
}
}
f[x][0]+=calc(maxv[x]);
} ll fet[MAXN],calsec[MAXN],cal[MAXN]; il void dfs2(rg int x)
{
if(fa[x])
{ // f[fa] shouldn't change
fet[x]=fetch(x);
cal[x]=calc(x);
f[fa[x]][1]-=fet[x];
f[fa[x]][0]-=fet[x];
rg int w=fw[fa[x]];
fw[fa[x]]=fw[x];
f[x][1]+=fetch(fa[x]);
f[x][0]=f[x][1];
if(maxv[fa[x]]==x)
{
f[fa[x]][0]-=cal[x];
f[fa[x]][0]+=calsec[fa[x]];
}
if(calc(fa[x])>calc(secv[x]))
{
secv[x]=fa[x];
if(calc(secv[x])>calc(maxv[x]))
swap(secv[x],maxv[x]);
}
calsec[x]=calc(secv[x]);
f[x][0]+=calc(maxv[x]); f[fa[x]][1]+=fet[x]; // restore
f[fa[x]][0]+=fet[x];
fw[fa[x]]=w;
if(maxv[fa[x]]==x)
{
f[fa[x]][0]-=calsec[fa[x]];
f[fa[x]][0]+=cal[x];
}
}
else
{
fet[x]=fetch(x);
calsec[x]=calc(secv[x]);
cal[x]=calc(x);
} for(rg int i=head[x];i;i=E[i].nx)
{
rg int y=E[i].to;
if(y==fa[x])
continue;
dfs2(y);
}
} int main()
{
freopen("treasure.in","r",stdin);
freopen("treasure.out","w",stdout);
rg int n=read<int>();
for(rg int i=1;i<n;++i)
{
rg int x=read<int>(),y=read<int>(),w=read<int>();
addedge(x,y,w);
addedge(y,x,w);
}
for(rg int i=1;i<=n;++i)
{
read(val[i]);
}
dfs1(1,0);
dfs2(1);
/* for(int i=1;i<=n;++i)
{
printf("%d:\n",i);
printf(" f0=%lld\tf1=%lld\n",f[i][0],f[i][1]);
}*/
for(rg int i=1;i<=n;++i)
{
printf("%lld\n",f[i][0]);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}

标解

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<bitset>
using namespace std;
typedef long long ll;
const int N=610000;
int fi[N],ne[N],len[N],to[N];
ll dp0[N],dp1[N];
ll ans[N],wushi0[N],wushi1[N],val[N];
int pE,n;
//0:考虑回到原点;1:不回到原点
void addE(int u,int v,int l)
{
pE++;to[pE]=v;len[pE]=l;
ne[pE]=fi[u];fi[u]=pE;
}
void dfs(int u,int fa)
{
ll mx=0;
for (int j=fi[u];j;j=ne[j])
{
if (to[j]==fa) continue;
dfs(to[j],u);
if (dp0[to[j]]-2*len[j]>0)
{
dp0[u]+=dp0[to[j]]-2*len[j];
mx=max(mx,len[j]+dp1[to[j]]-dp0[to[j]]);
}
else mx=max(mx,dp1[to[j]]-len[j]);
}
dp0[u]+=val[u];
dp1[u]=dp0[u]+mx;
}
void dfs2(int u,int fa,int le)
{
ans[u]=max(dp0[u]+max(wushi1[u]-le,(ll)0),dp1[u]+max(wushi0[u]-le*2,(ll)0));
ll mx1=0,mx2=0;
for (int j=fi[u];j;j=ne[j])
{
if (to[j]==fa) continue;
ll now;
if (dp0[to[j]]-2*len[j]>0) now=len[j]+dp1[to[j]]-dp0[to[j]];
else now=dp1[to[j]]-len[j];
if (now>mx1) {mx2=mx1;mx1=now;}
else if (now>mx2) mx2=now;
}
ll now;
if (wushi0[u]-2*le>0) now=le+wushi1[u]-wushi0[u];
else now=wushi1[u]-le;
if (now>mx1) {mx2=mx1;mx1=now;}
else if (now>mx2) mx2=now;
for (int j=fi[u];j;j=ne[j])
{
if (to[j]==fa) continue;
wushi0[to[j]]=dp0[u]-max((ll)0,dp0[to[j]]-2*len[j])+max((ll)0,wushi0[u]-2*le);
ll now;
if (dp0[to[j]]-2*len[j]>0) now=len[j]+dp1[to[j]]-dp0[to[j]];
else now=dp1[to[j]]-len[j];
if (now==mx1) wushi1[to[j]]=wushi0[to[j]]+mx2;
else wushi1[to[j]]=wushi0[to[j]]+mx1;
}
for (int j=fi[u];j;j=ne[j])
if (to[j]!=fa) dfs2(to[j],u,len[j]);
}
int main()
{
freopen("treasure.in","r",stdin);
freopen("treasure.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<n;i++)
{
int u,v,l;scanf("%d%d%d",&u,&v,&l);
addE(u,v,l);addE(v,u,l);
}
for (int i=1;i<=n;i++) scanf("%d",&val[i]);
dfs(1,0);
for (int j=fi[1];j;j=ne[j])
if (dp0[to[j]]-2*len[j]>0)
wushi0[to[j]]=dp0[1]-(dp0[to[j]]-2*len[j]);
else wushi0[to[j]]=dp0[1];
ll mx1=0,mx2=0;
for (int j=fi[1];j;j=ne[j])
{
ll now;
if (dp0[to[j]]-2*len[j]>0) now=len[j]+dp1[to[j]]-dp0[to[j]];
else now=dp1[to[j]]-len[j];
if (now>mx1) {mx2=mx1;mx1=now;}
else if (now>mx2) mx2=now;
}
for (int j=fi[1];j;j=ne[j])
{
ll now;
if (dp0[to[j]]-2*len[j]>0) now=len[j]+dp1[to[j]]-dp0[to[j]];
else now=dp1[to[j]]-len[j];
if (now==mx1) wushi1[to[j]]=wushi0[to[j]]+mx2;
else wushi1[to[j]]=wushi0[to[j]]+mx1;
}
ans[1]=dp1[1];
for (int j=fi[1];j;j=ne[j]) dfs2(to[j],1,len[j]);
for (int i=1;i<=n;i++) printf("%lld\n",ans[i]);
return 0;
}

test20181029 宝藏的更多相关文章

  1. 算法:poj1066 宝藏猎人问题。

    package practice; import java.util.Scanner; public class TreasureHunt { public static void main(Stri ...

  2. 【BZOJ-1924】所驼门王的宝藏 Tarjan缩点(+拓扑排序) + 拓扑图DP

    1924: [Sdoi2010]所驼门王的宝藏 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 787  Solved: 318[Submit][Stat ...

  3. zzulioj 1907小火山的宝藏交易(dfs记忆化搜索)

    #include <stdio.h> #include <algorithm> #include <string.h> #include <vector> ...

  4. codevs3196 黄金宝藏

    题目描述 Description 小毛终于到达宝藏点,他意外地发现有一个外星人(名叫Pluto).宝藏是一些太空黄金,有n堆排成一行,每堆中有xi颗黄金.小毛和Pluto决定轮流从中取出黄金,规则是每 ...

  5. bzoj 1924 [Sdoi2010]所驼门王的宝藏(构图,SCC,DP)

    Description Input 第一行给出三个正整数 N, R, C. 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室 ...

  6. (zzuli)1907 小火山的宝藏收益

    Description 进去宝藏后, 小火山发现宝藏有N个房间,且这n个房间通过N-1道门联通. 每一个房间都有一个价值为Ai的宝藏, 但是每一个房间也都存在一个机关.如果小火山取走了这个房间的宝藏, ...

  7. zzuli 1907: 小火山的宝藏收益 邻接表+DFS

    Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 113  Solved: 24 SubmitStatusWeb Board Description    ...

  8. [SDOI2010]所驼门王的宝藏

    题目描述 在宽广的非洲荒漠中,生活着一群勤劳勇敢的羊驼家族.被族人恭称为"先知"的Alpaca L. Sotomon是这个家族的领袖,外人也称其为"所驼门王". ...

  9. [51nod1474]宝藏图

    有n堆宝藏,每一堆宝藏有一个挖掘所需要的时间ti,有一个价值qi. 现在是做一个宝藏图.这个宝藏图是这样的,宝藏图的形状是一棵二叉树,二叉树刚好有k个叶子结点,从n堆宝藏中选k堆放到二叉树的叶子结点上 ...

随机推荐

  1. pyDay16

    内容来自廖雪峰的官方网站. 1.Python内建的filter()函数用于过滤序列. 2.和map()类似,filter()也接收一个函数和一个序列.和map()不同的是,filter()把传入的函数 ...

  2. P4099 [HEOI2013]SAO(树形dp)

    P4099 [HEOI2013]SAO 我们设$f[u][k]$表示以拓扑序编号为$k$的点$u$,以$u$为根的子树中的元素所组成的序列方案数 蓝后我们在找一个以$v$为根的子树. 我们的任务就是在 ...

  3. 20145204《java程序设计》课程总结

    ---恢复内容开始--- 20145204<java程序设计>课程总结 每周读书笔记链接汇总: · 20145204<java程序设计>第一周总结 · 20145204< ...

  4. AJAX,JSON,GSON

    AJAX将数据使用JSON格式发送给后端Servlet或其他语言解析. 对JSON内容使用GSON外扩展包进行分解,并使用(如查询用户名是否已经被注册), 最后使用Map集合设置新的返回状态码,并使用 ...

  5. Java回顾之ORM框架

    这篇文章里,我们主要讨论ORM框架,以及在使用上和JDBC的区别. 概述 ORM框架不是一个新话题,它已经流传了很多年.它的优点在于提供了概念性的.易于理解的数据模型,将数据库中的表和内存中的对象建立 ...

  6. Java回顾之一些基础概念

    类的初始化顺序 在Java中,类里面可能包含:静态变量,静态初始化块,成员变量,初始化块,构造函数.在类之间可能存在着继承关系,那么当我们实例化一个对象时,上述各部分的加载顺序是怎样的? 首先来看代码 ...

  7. tp5集成淘宝,微信,网易,新浪等第三方登录

    tp5集成淘宝,微信,网易,新浪等第三方登录 一.总结 一句话总结: 接口 链接 实现的话就是这些平台给的一个接口(链接),你通过这些接口登录进去之后,它会给你返回用户名,头像之类的信息,我们的网站存 ...

  8. 卸载oracle11g步骤图解

    卸载oracle11g步骤图解       重启电脑即可

  9. Vue.js组件设计原则

    页面上把每个独立可以交互的区域视为一个组件 每个组件对应一个工程目录,组件所需要的各种资源在这个目录下就近维护 页面不过是组件的容器,组件可以嵌套自由组合形成完整的页面

  10. bzoj1176

    题解: 和上一题差不多 就加上一个初始值 代码: #include<bits/stdc++.h> ; using namespace std; int n,m,cnt,s,sum[N],a ...