题意

分析

考场做法

一眼看出是支持换根的树形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. Cup fungus in Corvobado Nation Park,Costa Rica

  2. Mkdocs 搭建

    1. 利用pip安装mkdocs sudo pip install mkdocs 2.如果报pip不存在 或是 报权限错误,要不是pip没有安装,就是python里某个库没有关联上,这时候需要重新安装 ...

  3. mongodb的存储引擎

    mongodb版本为3.4 mongodb存储引起的一些概述 存储引擎是MongoDB的核心组件,负责管理数据如何存储在硬盘和内存上.从MongoDB 3.2 版本开始,MongoDB 支持多数据存储 ...

  4. 2017-2018-1 JaWorld 第六、七周作业

    2017-2018-1 JaWorld 第六.七周作业 修改需求规格说明书 上次的<需求规格说明书>初稿有哪些不足? 王译潇同学回答:   1. 引言和目的性考虑的不是很周全.   2. ...

  5. linuxI/O重定向

    假设有这么一段python3程序: import sys ")sys.stderr.write("stderr1 ") 现在想要把程序的输出以及错误信息都存在文件中. 一 ...

  6. c++ 字符串拷贝以及合并

    #include<iostream> #include<string> using namespace std; class stringfun { ]; public: vo ...

  7. python判断key是否存在

    d = {: , : , : , : , : , : } def is_key_present(x): if x in d: print('Key is present in the dictiona ...

  8. rxjava rxandroid使用遇到的坑

    今天在解决一个界面加载本地数据库数据的时候,使用rxjava在指定io线程操作是遇到一个问题,即使指定了在io线程操作,可是界面还是卡顿,最后通过打印线程Thread.currentThread(). ...

  9. C#用大石头Xcode做数据底层注意事项

    1.记得添加XCode.dll 和NewLife.Core.dll 2.记得把程序的框架改为 .net Framework4

  10. poj2411 轮廓线dp裸题

    题意:用12的骨牌覆盖nm的矩阵的方案数 题解:dp[i][j]表示枚举到了第i行,j状态的方案数,三种转移,向上的,要求不是第一行而且上面的没有覆盖过,向下的,要求不是第一列而且左边没有覆盖过,不放 ...