题解 CF1016F【Road Projects】
题意
给一颗 $n$ 个结点的带权树,$q$ 组询问在树上加一条长度为 $x$ 的边后 $1\to n$ 的最短路的最大值。
$n,q\le 3\times 10^5$.
思路
锐评:看不懂某篇单调栈,于是来写个前缀和。
照样把 $1\to n$ 的链拉出来并标记它们,令它们的 $v_i=1$,链长为 $t$。
令 $p_i$ 表示被标记的点 $i$ 到 $1$ 的权值和,$d_i$ 表示被标记的点 $i$ 到它不被标记的儿子的子树中最大的距离,$s_i$ 表示点 $i$ 不被标记的儿子的子树中的点数和。
首先答案不大于 $p_n$。考虑 $\exists v_i=1,s_i\ge 2$,则连接它的链外子树中任意两点,不改变最短路,答案为 $p_n$。
否则,考虑在 $i$ 或它的的链外子树和 $j$ 或它的的链外子树中选两个点连边,答案为$$\max_{i<j,v_{i,j}=1}(p_i+d_i-p_j+d_j+p_n+x)$$
可以发现,答案只与前四项有关,处理出 $p_i+d_i$ 的前缀 $\max pr_i$ 和取到的位置 $prp_i$,处理出 $-p_i+d_i$ 的后缀 $\max sf_i$ 和取到的位置 $sfp_i$,答案则为$$\max_{i=1}^{t-1} (pr_i+sf_{i+1})+p_n+x$$
特别地,当最优决策相邻并且都没有链外子树时不能取到。
做完了,时间复杂度 $\Theta(n+q)$。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
}
const int N=3e5+10;
struct Edge{
int to,nxt,w;
}a[N<<1];
int n,q,siz[N],fa[N],cnt,head[N];
ll p[N],d[N];
bool vis[N];
vector<int>vec;
inline void add(int u,int v,int w){
cnt++;
a[cnt].to=v;
a[cnt].nxt=head[u];
a[cnt].w=w;
head[u]=cnt;
}
inline void dfs1(int rt,int f){
fa[rt]=f;
for(int i=head[rt];i;i=a[i].nxt){
int t=a[i].to;
if(t==f) continue;
dfs1(t,rt);
}
}
inline void dfs2(int rt){
siz[rt]=1;
if(vis[rt]) vec.push_back(rt);
for(int i=head[rt];i;i=a[i].nxt){
int t=a[i].to;
if(t==fa[rt]) continue;
if(vis[t])
p[t]=p[rt]+a[i].w;
dfs2(t);
if(!vis[t])
siz[rt]+=siz[t],
d[rt]=max(d[rt],d[t]+a[i].w);
}
}
bool fl;
int prp[N],sup[N];
ll pr[N],sf[N],sep[N],ses[N],ans=-2e18;
int main(){
n=read(),q=read();
for(int i=1;i<n;i++){
int u=read(),v=read(),w=read();
add(u,v,w),add(v,u,w);
}
dfs1(1,0);
for(int i=n;i;i=fa[i])
vis[i]=1;
vec.push_back(0);
dfs2(1);
for(int i=1;i<=n;i++)
if(siz[i]>=3)
fl=1;
pr[0]=sf[vec.size()]=-2e18;
for(int i=1;i<vec.size();i++){
ll tmp=p[vec[i]]+d[vec[i]];
if(tmp>pr[i-1]) pr[i]=tmp,prp[i]=i;
else pr[i]=pr[i-1],prp[i]=prp[i-1];
}
for(int i=vec.size()-1;i;i--){
ll tmp=-p[vec[i]]+d[vec[i]];
if(tmp>sf[i+1]) sf[i]=tmp,sup[i]=i;
else sf[i]=sf[i+1],sup[i]=sup[i+1];
}
for(int i=1;i<vec.size();i++){
if(prp[i-1]==i-1&&sup[i]==i&&siz[vec[i-1]]==1&&siz[vec[i]]==1) continue;
ans=max(ans,pr[i-1]+sf[i]);
}
ans+=p[n];
for(int i=1;i<vec.size()-2;i++)
ans=max(ans,p[vec[i]]+p[n]-p[vec[i+2]]);
for(int i=1;i<vec.size();i++){
if(siz[vec[i]]==1) continue;
if(i!=1) ans=max(ans,p[vec[i-1]]+d[vec[i]]+p[n]-p[vec[i]]);
if(i!=vec.size()-1) ans=max(ans,p[vec[i]]+d[vec[i]]+p[n]-p[vec[i+1]]);
}
while(q--){
int x=read();
write(fl?p[n]:min(ans+x<=0?p[n]:ans+x,p[n])),putc('\n');
}
flush();
}
再见 qwq~

浙公网安备 33010602011771号