2018年9月24日提高組模擬賽 T2 小x遊世界樹
阿新 • • 發佈:2018-12-11
大意
給定一棵樹,求出從哪個點跑最短路使得最短路徑的和最小
思路
二次掃描換根法
先用一遍求出一個點的最短路,然後考慮換根帶來的最短路影響
以樣例為例,假設我們現在要從1換根到2 我們考慮換根會帶來的影響,發現1和3(綠點)多走了2那條邊,而2和4少走1(紅點)那條邊 這樣我們就得到了狀態轉移方程
通不通俗,易不易懂
程式碼
#pragma GCC optimize(2)
#include<cstring>
#include<cstdio>
#define ri register int
#define r(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;const int N=1400001;
int n,l[N],tot=1,yh[N],x,y,z,ans=1,num[N];
struct node{int next,to,w;}e[N<<1];
inline void add(ri u,ri v,ri w){e[++tot]=(node){l[u],v,w};l[u]=tot;return;}
bool vis[N]={0};
long long f[N];
inline int read()//輸入優化
{
int f=0,d=1;char c;
while(c=getchar(),c<48 ||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>47&&c<58)f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline void write(long long x)//輸出優化
{
if(x<0) {x=-x;putchar('-');}
if(x>9)write(x/10);putchar(x%10+48);
return;
}
inline void dfs(ri x)//求單點最短路
{
vis[x]=true;num[x]++;
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(!vis[y])
{
dfs(y);
num[x]+=num[y];
f[1]+=e[i].w*num[y];
}
}
return;
}
inline void dp(ri x)//換根
{
vis[x]=true;
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(!vis[y])
{
f[y]=f[x]+(n-num[y])*(e[i^1].w)-num[y]*(e[i].w);
dp(y);
if(f[y]<f[ans]) ans=y;
if(f[y]==f[ans]) if(y<ans) ans=y;
}
}
return;
}
signed main()
{
n=read();
r(i,1,n) yh[i]=read();
r(i,1,n-1)
{
x=read();y=read();z=read();
add(x,y,z-yh[x]);add(y,x,z-yh[y]);
}
dfs(1);
memset(vis,0,sizeof(vis));
dp(1);
write(ans);putchar(10);write(f[ans]);//輸出
}