YYHS-魏传之长坂逆袭(梦回三国系列T1)
题目描述
众所周知,刘备在长坂坡上与他的一众将领各种开挂,硬生生从曹操手中逃了出去,随后与孙权一起火烧赤壁、占有荆益、成就霸业。而曹操则在赤壁一败后再起不能,终生无力南下。
建安二十五年(220年),曹操已到风烛残年,但仍难忘当年长坂的失误,霸业的破灭。他想如果在刘备逃亡的路中事先布下一些陷阱,便能拖延刘备的逃脱时间了。你作为曹操身边的太傅,有幸穿越到了208年的长坂坡,为大魏帝国贡献一份力,布置一些陷阱。但时空守卫者告诉你你不能改变历史,不能拖增大刘备的最大逃脱时间,但你身为魏武之仕,忠心报国,希望能添加一些陷阱使得刘备不论怎么逃跑所用的时间都一样。
已知共有n个据点,n-1条栈道,保证据点联通。1号据点为刘备军逃跑的起点,当刘备军跑到某个据点后不能再前进时视为刘备军逃跑结束。在任意一个栈道上放置1个陷阱会使通过它的时间+1,且你可以在任意一个栈道上放置任意数量的陷阱。
现在问你在不改变刘备军当前最大逃跑时间的前提下,需要添加最少陷阱,使得刘备军的所有逃脱时间都尽量的大。
输入
第一行一个数n,表示据点个数。
接下来n-1行每行三个数,ai、bi、ti,表示从据点ai通过第i个栈道到bi耗时ti
输出
仅包含一个数,为需要添加的最少陷阱数。
样例输入
3 1 2 1 1 3 3
样例输出
2
提示
【数据规模和约定】
对于 5%的数据,1<=n<=100000,1<=ti<=200000
对于 100%的数据,1<=n<=500000,0<ti<=1000000
题解
刚看到的时候还没有什么头绪,题目也读了一会儿
后来再看感觉可以暴力
我们先dfs找到最长的一条路径
然后我们找每条路径需要的陷阱数,不难发现 如果一个点的所有子树所需要的最小陷阱数为x的话,其实放在子树上不是最优的,我们可以把x个陷阱放在当前点上
1 #include<bits/stdc++.h> 2 #define N 500005 3 #define ll long long 4 using namespace std; 5 int n,x,y,z,tot; 6 ll Max,ans; 7 int head[N]; 8 ll tr[N]; 9 struct node{ 10 int next,to,dis; 11 }e[2*N]; 12 void add(int x,int y,int z){ 13 e[++tot].next=head[x]; 14 head[x]=tot; 15 e[tot].to=y; 16 e[tot].dis=z; 17 } 18 void dfs(int u,int pre,ll s){ 19 bool flag=false; 20 for (int i=head[u];i;i=e[i].next){ 21 int v=e[i].to; 22 if (v==pre) continue; 23 flag=true; 24 dfs(v,u,s+e[i].dis); 25 } 26 if (!flag){ 27 if (s>Max) Max=s; 28 return; 29 } 30 } 31 void Dfs(int u,int pre,int s){ 32 ll Min=1e12; 33 bool flag=false; 34 for (int i=head[u];i;i=e[i].next){ 35 int v=e[i].to; 36 if (v==pre) continue; 37 flag=true; 38 Dfs(v,u,s+e[i].dis); 39 Min=min(Min,tr[v]); 40 } 41 if (!flag){ 42 tr[u]=Max-s; 43 return; 44 } 45 if (!Min){ 46 tr[u]=0; 47 return; 48 } 49 for (int i=head[u];i;i=e[i].next){ 50 int v=e[i].to; 51 if (v==pre) continue; 52 tr[v]-=Min; 53 } 54 tr[u]=Min; 55 } 56 int main(){ 57 scanf("%d",&n); 58 for (int i=1;i<=n-1;i++) 59 scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z); 60 dfs(1,0,0); 61 Dfs(1,0,0); 62 for (int i=1;i<=n;i++) ans+=tr[i]; 63 printf("%lld\n",ans); 64 return 0; 65 }