传送门
题解
一开始想的是先求出 (1,n) 的单源最短路,之后枚举中转点把两段拼起来,几乎写完了之后才发现我这个想法根本就不对。(因为没办法简单地把两段路径拼在一起)重构了,用时巨长。
其实,按照上面的思路继续,应该也不难想出正解。
变换一下视角,把 (1 - n) 的路径单独提出来,以后的操作基于这条链。
这条链上可能挂着一些子树,分类讨论。
- 如果有大小超过 (2) 的子树(包括链上的那个点),就可以在子树内连边,不对答案造成影响。
- 如果没有上述子树,说明链上顶多有一条边伸出去。此时继续分类讨论。
- 对于每一个链上的点,都可以隔一个链上相邻的点连边。(按照贪心,不会隔着更多的点连边)
- 对于每一个伸出去的点,都可以和链上相邻的两点连边。同时,也可以和前面其他伸出去的点连边。
细节略多,如果考试的话我八成写挂了吧...现在要细节再细节...
代码
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f,N = 3e5+10;
#define ll long long int
inline ll read()
{
ll ret=0;char ch=' ',c=getchar();
while(!(c>='0'&&c<='9')) ch=c,c=getchar();
while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
return ch=='-'?-ret:ret;
}
int n,m;
int siz;
ll dis[N],val,lst;
int ecnt=-1,head[N];
int stk[N],top;
bool vis[N];
bool flag;
inline void init()
{
memset(head,-1,sizeof(head));
ecnt=-1;
}
struct edge
{
int nxt,to,w;
}a[N<<1];
inline void add_edge(const int x,const int y,const int w)
{
a[++ecnt]=(edge){head[x],y,w};
head[x]=ecnt;
}
void find_chain(const int u,const int fa)
{
if(!flag) stk[++top]=u,vis[u]=1;
if(u==n) flag=1;
for(int i=head[u];~i;i=a[i].nxt)
{
int v=a[i].to;
if(v==fa) continue;
dis[v]=dis[u]+a[i].w;
find_chain(v,u);
}
if(!flag) top--,vis[u]=0;
}
void dfs(const int u)
{
siz++,vis[u]=1;
for(int i=head[u];~i;i=a[i].nxt)
{
int v=a[i].to;
if(vis[v]) continue;
val+=a[i].w;
dfs(v);
}
}
int main()
{
init();
n=read(),m=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read(),w=read();
add_edge(u,v,w),add_edge(v,u,w);
}
find_chain(1,-1);
ll l=1e18;
dis[0]=-1e18,dis[n+1]=1e18;
stk[top+1]=n+1; //处理边界越界问题
for(int i=1;i<=top;i++)
{
// printf("stk[%d]=%d
",i,stk[i]);
// printf("dis[%d]=%lld
",stk[i],dis[stk[i]]);
siz=val=0;
if(i>2) l=min(l,dis[stk[i]]-dis[stk[i-2]]);
dfs(stk[i]);
if(siz>=3) {l=0LL;break;}
if(val) l=min(l,min(dis[stk[i]]-dis[stk[i-1]]-val,dis[stk[i+1]]-dis[stk[i]]-val));//我tm无语,这个+1的边界越界调死我了
if(lst&&val) l=min(l,dis[stk[i]]-val-lst);
if(val) lst=max(lst,val+dis[stk[i]]);
}
//printf("l=%lld
",l);
for(int i=1;i<=m;i++)
{
int x=read();
printf("%lld
",min(dis[n],dis[n]+x-l));
}
return 0;
}
/*
8 5
7 3 2
3 2 8
1 7 11
4 6 13
8 5 3
2 6 14
4 8 5
*/