解析
好题
意思就是我没做出来
稍微分析一下就可以发现加边的位置始终是一样的
换句话说询问完全可以O1
关键就是找到这条边加在哪里
一开始我完全把这道题看成了彻头彻尾的数据结构题
容易想到二分答案
然后上个树状树组搞一搞就行了
但是遇到一个关键的问题
它无法解决加边必须是非树边的问题
于是又搞巴搞巴整了个线段树并且把离散化的去重干掉,开始乱搞
然后就T了…
本来线段树常数就大我的那个东西暴力修改还自带好几倍常数…
俩log根本过不去3e5
无奈之下看了题解
真的很巧妙
复杂度和实现难度双重碾压我qwq
把1-n的链提出来
然后分类一下就迎刃而解了
upd:代码有问题!(CF没卡掉…但是显然是假的)
求链上的min时不一定相邻,而是应该提出来一些东西维护一个最小值
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
#define debug(a,b) fprintf(stderr,a,b)
const int N=3e5+100;
const int M=3e6+100;
const int mod=998244353;
inline ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;
}
int n,m;
int fi[N],cnt;
struct node{int to,nxt,w;
}p[N<<1];
inline void addline(int x,int y,int w){p[++cnt]=(node){y,fi[x],w};fi[x]=cnt;return;
}
ll ans=3e14;
int fa[N],siz[N],hson[N];
ll dis[N];
void dfs(int x,int f){fa[x]=f;siz[x]=1;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dis[to]=dis[x]+p[i].w;dfs(to,x);siz[x]+=siz[to];}return;
}
ll add[N];
void find(int x){if(!x) return;if(fa[fa[x]]){ans=min(ans,dis[x]-dis[fa[fa[x]]]);}hson[fa[x]]=x;if(siz[x]-siz[hson[x]]-1>=2){ans=0;return;}for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==fa[x]||to==hson[x]) continue;add[x]=p[i].w;}for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to!=hson[x]) continue;if(add[x]||add[to]) ans=min(ans,1ll*p[i].w-add[x]-add[to]);}find(fa[x]);
}
int main(){#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);#endifmemset(fi,-1,sizeof(fi));cnt=-1;n=read();m=read();for(int i=1;i<n;i++){int x=read(),y=read(),w=read();addline(x,y,w);addline(y,x,w);}dfs(1,0);find(n);for(int i=1;i<=m;i++){int x=read();printf("%lld\n",dis[n]-max(0ll,ans-x));}return 0;
}
/*
3 1
3 1 33 2
1 1 2
3 1 3
*/