原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=6201
题目大意:一些城市及其之间的道路构成了一棵树。对于某一种物品,在城市 i 的价格是 ai单位金钱 ,而在道路上每走1单位长度就会花费1单位金钱。问任意选定买入该物品的城市和卖出该物品的城市,每个物品最大获利是多少。
可以发现,如果一个城市的价格加上旅途费用后的单价比旅途终点的价格低,则在终点买入肯定不如在起点买入,于是可以用起点的单价加旅途的费用作为终点的新的单价,然后继续更新其他城市的单价。显然,如果从价格较低的城市开始依次更新其他城市的单价,然后比对每个城市的最小单价和原来的价格之差得到答案。
于是就有了一个比较裸的算法,从单价小的城市更新单价大的城市就可以了。
但是,这样直接写会被特殊构造的数据卡成TLE(今天人品还不错,没有被卡,笑CRY.......
如下面的数据点:
1
8
1 2 3 4 1000 1001 10002 1003
1 5 100
2 5 98
3 5 96
4 5 94
5 6 1
6 7 1
7 8 1
在这个数据点里,该算法会先用节点1更新节点5到节点8,然后又会用节点2更新节点5到节点8,然后是节点3,节点4。这个算法的实际时间复杂度已经达到了O(n^2),妥妥地会TLE
但是可以在这个基础上进行改进。
令F( x)代表以节点x为起点,到其他城市的单价减距离的最大值。
显然如果以节点x进行搜索完一次以后,不可能再被其他点更新,于是可以确定每个点只会被搜索一次,于是算法时间复杂度是O(n)的,可以确定不会被特殊数据卡掉
代码:
#include <bits/stdc++.h>
using namespace std;
inline void read(int &x){
char ch;
bool flag=false;
for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
x=flag?-x:x;
}
inline void read(long long &x){
char ch;
bool flag=false;
for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
x=flag?-x:x;
}
int const maxn=200000;
int const maxm=500000;
int pre[ maxm ], now [ maxn ] ,son [ maxm ] , v[ maxm] ,tot;
bool vis[maxn];
int n;
int tmp[maxn];
int ttt[maxn];
struct zy{
int v,id;
}a[maxn];
void build(int a ,int b, int c ){
pre[++tot]=now[a];
now[a]=tot;
son[tot]=b;
v[tot]=c;
}
int Max[ maxn ];
int cnt=0;
void dfs(int x,int fa){
if (vis[x])
return ;
for (int p=now[x];p;p=pre[p])
if (son[p]!=fa)
{
if ( tmp[ son[p] ] > tmp[ x ]+v[p])
dfs( son[p] , x );
Max[ x ] = max( Max[ x ] , Max[ son[p] ] -v[p] );
}
cnt++;
vis[x]=1;
}
bool cmpv(zy A , zy B){
return A.v<B.v;
}
void doit(){
read(n);
tot=0;
memset(now,0,sizeof(now));
memset(vis,0,sizeof(vis));
for (int i=1;i<=n;i++)
{
read(a[i].v);
a[i].id=i;
tmp[i]=a[i].v;
ttt[i]=a[i].v;
}
for (int i=1;i<n;i++)
{
int a,b,c;
read(a); read(b); read(c);
build( a,b,c);
build( b, a,c);
}
sort(a+1,a+n+1,cmpv);
for (int i=1;i<=n;i++)
Max[i]=tmp[i];
for (int i=1;i<=n;i++)
if (!vis[ a[i].id ])
dfs( a[i].id , 0 );
int ans=0;
for (int i=1;i<=n;i++)
ans=max(Max[ i ]-tmp[i],ans);
printf("%d\n",ans);
}
int main(){
int T;
read(T);
for (int i=1;i<=T;i++)
doit();
return 0;
}