传送门:luoguP1084
题解
求最小值首先二分答案,记录每个点倍增向上跳的信息。
设当前二分答案为 m i d mid mid
跳不到根节点的军队的位置是唯一确定的。
对于跳的到的军队结点 i i i取出其到根后仍能多走的距离 r e s 1 = m i d − d i s ( 1 , i ) res1=mid-dis(1,i) res1=mid−dis(1,i)。
同时 d f s dfs dfs判断根节点的儿子 c h 1 i ch_{1i} ch1i子树中哪些子树没有被覆盖完,同样记录距离为 r e s 2 = d i s ( 1 , c h 1 i ) res2=dis(1,ch_{1i}) res2=dis(1,ch1i)
将 r e s 1 , r e s 2 res1,res2 res1,res2都按降序排序,贪心填充即可。
p.s.需要注意:对于某个没有被覆盖完的子树 x x x,显然由自己子树中的走到根有闲余的点来填充最优,所以枚举到 x x x时,先判断 x x x子树中有闲余的且闲余最小的点是否被用过,如果用过不能选再判断当前 r e s 1 m a x res1_{max} res1max是否可用。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+100;
typedef long long ll;
int n,m,d[N],loc[N],ban[N],p[N],ed[N],used[N];
int head[N],nxt[N<<1],to[N<<1],w[N<<1],tot;
ll dis[17][N],ans,val[N];int f[17][N],dr[N];
struct P{
int id;ll v;
P(int id_=0,ll v_=0):id(id_),v(v_){};
bool operator<(const P&ky)const{
return v<ky.v;
}
}A,B;
vector<P>dyd;
vector<P>bxd;
char cp;
inline void rd(int &x)
{
cp=getchar();x=0;
for(;!isdigit(cp);cp=getchar());
for(;isdigit(cp);cp=getchar()) x=(x<<3)+(x<<1)+(cp^48);
}
inline void lk(int u,int v,int vv)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=vv;}
void dfs(int x)
{
ed[x]=1;
for(int j,i=head[x];i;i=nxt[i]){
j=to[i];if(j==f[0][x]) continue;
d[j]=d[x]+1;f[0][j]=x;dis[0][j]=(ll)w[i];
ed[x]=0;dfs(j);
}
}
inline void upp(int id,ll lim)
{
int i,x=p[id];
for(i=15;(~i) && lim;--i)
if(lim>=dis[i][x] && f[i][x]>1){
lim-=dis[i][x];
x=f[i][x];
}
if(lim>dis[0][x]){
loc[id]=0;val[id]=lim-dis[0][x];
dyd.push_back(P(id,val[id]));
for(i=min(i+1,15);(~i) && f[i][x]>1;x=f[i][x]);
if(!dr[x] || val[dr[x]]>val[id]) dr[x]=id;
}else{
loc[id]=x;ban[x]=1;
}
}
bool dfck(int x)
{
if(ed[x]) return true;
for(int j,i=head[x];i;i=nxt[i]){
j=to[i];if(j==f[0][x] || ban[j]) continue;
if(dfck(j)) return true;
}
return false;
}
inline bool ck(ll lim)
{
int i,j;bool re=true;
for(i=1;i<=m;++i)
upp(i,lim);
for(i=head[1];i;i=nxt[i]){
j=to[i];if(ban[j]) continue;
if(dfck(j)) bxd.push_back(P(j,w[i]));
}
sort(bxd.begin(),bxd.end());
sort(dyd.begin(),dyd.end());
for(i=bxd.size()-1,j=dyd.size()-1;(~i) && (~j);--i){
A=bxd[i];
if(dr[A.id] && (!used[dr[A.id]])){used[dr[A.id]]=1;continue;}
for(;(~j) && used[dyd[j].id];--j);
if(j<0 || A.v>dyd[j].v) break;used[dyd[j].id]=1;
}
if((~i)) re=false;
for(i=1;i<=m;++i) ban[loc[i]]=used[i]=0;
dyd.clear();bxd.clear();
for(i=head[1];i;i=nxt[i]) dr[to[i]]=0;
return re;
}
int main(){
int i,j,x,y,z;ll l,r,mid,ori;
rd(n);
for(i=1;i<n;++i){
rd(x);rd(y);rd(z);ans+=z;
lk(x,y,z);lk(y,x,z);
}
rd(m);
for(i=1;i<=m;++i) rd(p[i]);
dfs(1);
for(i=1;i<=15;++i)
for(j=2;j<=n;++j){
f[i][j]=f[i-1][f[i-1][j]];
dis[i][j]=dis[i-1][j]+dis[i-1][f[i-1][j]];
}
l=0;r=ori=ans;ans++;
for(;l<=r;){
mid=(l+r)>>1;
if(ck(mid)) r=(ans=mid)-1;
else l=mid+1;
}
if(ans>ori) ans=-1LL;
printf("%lld",ans);
return 0;
}