【BZOJ3743】[Coci2015]Kamp
Description
一顆樹n個點,n-1條邊,經過每條邊都要花費一定的時間,任意兩個點都是聯通的。
有K個人(分佈在K個不同的點)要集中到一個點舉行聚會。
聚會結束後需要一輛車從舉行聚會的這點出發,把這K個人分別送回去。
請你回答,對於i=1~n,如果在第i個點舉行聚會,司機最少需要多少時間把K個人都送回家。
Input
第一行兩個數,n,K。
接下來n-1行,每行三個數,x,y,z表示x到y之間有一條需要花費z時間的邊。
接下來K行,每行一個數,表示K個人的分佈。
Output
輸出n個數,第i行的數表示:如果在第i個點舉行聚會,司機需要的最少時間。
Sample Input
7 2
1 2 4
1 3 1
2 5 1
2 4 2
4 7 3
4 6 2
3
7
1 2 4
1 3 1
2 5 1
2 4 2
4 7 3
4 6 2
3
7
Sample Output
11
15
10
13
16
15
10
15
10
13
16
15
10
HINT
【資料規模】
K <= N <= 500000
1 <= x,y <= N, 1 <= z <= 1000000
題解:我們先高出這k個點的虛樹,先考慮出發點u這個點是虛樹上的點,且必須返回出發點時答案是什麼。顯然答案就是這個虛樹的所有邊的長度之和*2。
那麼如果要返回出發點呢?如果我們再v結束,那麼答案就會減去dis(u,v),那麼顯然dis(u,v)越大越好,所以樹形DP求一下每個點到虛樹上點的距離最大值即可。
然後如果u不在虛樹上呢?那麼它還要先走到虛樹上,所以再維護一下每個點到虛樹上點的距離最小值即可。
程式碼還是很不可讀的~
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn=500010;
ll ans;
int to[maxn<<1],next[maxn<<1],val[maxn<<1],head[maxn],p[maxn],q[maxn],s[maxn],fa[maxn],Q[maxn],st[maxn];
ll dep[maxn],f[maxn][2],g[maxn],h[maxn][2],k[maxn];
int n,m,cnt,top,np,mp;
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
void add(int a,int b,int c)
{
to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
void dfs(int x)
{
p[x]=++p[0],Q[p[0]]=x;
for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[x]) dep[to[i]]=dep[x]+val[i],fa[to[i]]=x,dfs(to[i]);
q[x]=p[0];
}
int main()
{
n=rd(),m=rd();
int i,a,b,c,x,y;
ll d;
memset(head,-1,sizeof(head));
for(i=1;i<n;i++) a=rd(),b=rd(),c=rd(),add(a,b,c),add(b,a,c);
dfs(1);
np=n,mp=0;
memset(f,0xc0,sizeof(f)),memset(g,0xc0,sizeof(g)),memset(h,0x3f,sizeof(h)),memset(k,0x3f,sizeof(k));
for(i=1;i<=m;i++) x=s[i]=rd(),f[x][0]=g[x]=h[x][0]=k[x]=0,np=min(np,p[x]),mp=max(mp,p[x]);
top=1;
for(i=1;i<=n;i++) if(p[i]<=np&&q[i]>=mp&&dep[i]>=dep[top]) top=i;
for(i=n;i>=2;i--)
{
x=Q[i],y=fa[x],d=dep[x]-dep[y];
if(f[y][0]>f[x][0]+d) f[y][1]=max(f[y][1],f[x][0]+d);
else f[y][1]=f[y][0],f[y][0]=f[x][0]+d;
if(!h[x][0]&&x!=top) h[y][0]=0,ans+=(dep[x]-dep[y])<<1;
if(h[y][0]<h[x][0]+d) h[y][1]=min(h[y][1],h[x][0]+d);
else h[y][1]=h[y][0],h[y][0]=h[x][0]+d;
}
for(i=2;i<=n;i++)
{
x=Q[i],y=fa[x],d=dep[x]-dep[y],g[x]=max(g[x],g[y]+d),k[x]=min(k[x],k[y]+d);
if(f[y][0]==f[x][0]+d) g[x]=max(g[x],f[y][1]+d);
else g[x]=max(g[x],f[y][0]+d);
if(h[y][0]==h[x][0]+d) k[x]=min(k[x],h[y][1]+d);
else k[x]=min(k[x],h[y][0]+d);
}
for(i=1;i<=n;i++) printf("%lld\n",ans+2*min(k[i],h[i][0])-max(g[i],f[i][0]));
return 0;
}