题意

分析

考场做法

一眼看出是支持换根的树形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. 2018-2019 ACM-ICPC, Asia Seoul Regional Contest

    ProblemA Circuits Solved. 题意: 有$n$个矩形,可以放两条平行与$x$轴的线,求怎么放置两条无线长的平行于$x$轴的线,使得他们与矩形相交个数最多 如果一个矩形同时与两条线 ...

  2. JS在if中的强制类型转换

    JS在if中的强制类型转换 众所周知,JS在很多情况下会进行强制类型转换,其中,最常见两种是: 1.使用非严格相等进行比较,对==左边的值进行类型转换 2.在if判断时,括号内的值进行类型转换,转化为 ...

  3. c++第二十一天

    p115~p118: 1.区分int *p[4];和int (*p)[4];.前者是整型指针的数组,后者是指向含有4个整数的数组. 2.规避上述问题的方法就是:使用 auto和 decltype. 3 ...

  4. bzoj1009 / P3193 [HNOI2008]GT考试

    P3193 [HNOI2008]GT考试 设$f[i][j]$表示主串匹配到第$i$个位置,不吉利数字匹配到第$j$个位置 $g[i][j]$表示加上某数字使子串原来最多能匹配到第$i$个数字,现在只 ...

  5. 20145333 《网络对抗技术》 PC平台逆向破解

    20145333 <网络对抗技术> PC平台逆向破解 20145333 <网络对抗技术> PC平台逆向破解 Shellcode注入 基础知识 Shellcode实际是一段代码, ...

  6. 【javascript】数据结构-集合

    <!DOCTYPE html> <html> <head> <title>集合</title> <meta charset=" ...

  7. Ubuntu16.04 国内更新源

    在修改source.list之前要先备份 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak 替换内容到source.list中 阿里云源: ...

  8. POJ 1625 Censored!(AC自动机->指针版+DP+大数)题解

    题目:给你n个字母,p个模式串,要你写一个长度为m的串,要求这个串不能包含模式串,问你这样的串最多能写几个 思路:dp+AC自动机应该能看出来,万万没想到这题还要加大数...orz 状态转移方程dp[ ...

  9. Mininet 跑一个简单的ping测试

    安装地址:https://github.com/mininet/mininet/wiki/Mininet-VM-Images 登录用户:mininet 密码:mininet 执行命令:sudo mn ...

  10. MaintainableCSS 《可维护性 CSS》 --- 模板篇

    什么是模块(Modules) ? 模块是一个特别的独立单元,可以与其他模块组合以形成更复杂的结构. 在客厅里,我们可以认为电视,沙发和墙艺术是模块.它们聚在一起创造一个可用的房间. 如果我们把其中一个 ...