树形dp求出每个点的到最远黑点的距离 和 这个点到所有最远黑点的路径的交 的另一端(lca也可以顺便记录),然后树上差分标记一下,统计出每个点被路径交覆盖了几次,由此可以计算答案。
#include<bits/stdc++.h> char ib[10000007],*ip=ib; int _(){ int x=0; while(*ip<48)++ip; while(*ip>47)x=x*10+*ip++-48; return x; } typedef long long i64; const int N=1e5+7; const i64 inf=1ll<<60; struct edge{ int to,nx,v; }e[N*2]; int n,m,e0[N],ep=2,ans=-1,at,fa[N],t[N]; bool is[N]; struct D1{ i64 md; int w; void upd(const D1&d,int w0){ if(d.md>md)*this=d; else if(d.md==md)w=w0; } D1 operator+(int x){ return (D1){md+x,w}; } }v1[N],v2[N],D1_nul=(D1){-inf,0}; struct D2{ i64 md; int w,lca; void upd(const D1&d,int w0){ if(d.md>md)md=d.md,w=d.w,lca=w0; else if(d.md==md)w=lca=w0; } void ins(int w0){ ++t[w0]; ++t[w]; --t[lca]; --t[fa[lca]]; } }d2[N],D2_nul=(D2){-inf,0,0}; void f1(int w,int pa){ fa[w]=pa; v1[w]=is[w]?(D1){0,w}:D1_nul; for(int i=e0[w];i;i=e[i].nx){ int u=e[i].to; if(u==pa)continue; f1(u,w); v1[w].upd(v1[u]+e[i].v,w); } } int cs[N],cp=0; void f2(int w){ cp=0; for(int i=e0[w];i;i=e[i].nx){ int u=e[i].to; if(u!=fa[w])cs[++cp]=i; } v2[cp+1]=D1_nul; for(int t=cp;t;--t){ int i=cs[t],u=e[i].to; v2[t]=v2[t+1]; v2[t].upd(v1[u]+e[i].v,w); } D1 v3=is[w]?(D1){0,w}:D1_nul; for(int t=1;t<=cp;++t){ int i=cs[t],u=e[i].to; d2[u]=d2[w]; d2[u].upd(v2[t+1],w); d2[u].upd(v3,w); d2[u].md+=e[i].v; v3.upd(v1[u]+e[i].v,w); } for(int i=e0[w],t=1;i;i=e[i].nx){ int u=e[i].to; if(u!=fa[w])f2(u); } if(is[w]){ d2[w].upd(v1[w],w); d2[w].ins(w); } } void f3(int w){ for(int i=e0[w];i;i=e[i].nx){ int u=e[i].to; if(u==fa[w])continue; f3(u); t[w]+=t[u]; } if(!is[w]){ if(t[w]>ans)ans=t[w],at=0; if(t[w]==ans)++at; } } int main(){ fread(ib,1,sizeof(ib),stdin); n=_(),m=_(); int rt=n; for(int i=1;i<=m;++i)is[_()]=1; for(int i=1,a,b,c;i<n;++i){ a=_(),b=_(),c=_(); e[ep]=(edge){b,e0[a],c};e0[a]=ep++; e[ep]=(edge){a,e0[b],c};e0[b]=ep++; } f1(rt,0); d2[rt]=is[rt]?(D2){0,rt,rt}:D2_nul; f2(rt); f3(rt); printf("%d %d\n",ans,at); return 0; }
时间: 2024-10-04 09:24:42