JDOJ 1062 过路费
Description
在某个遥远的国家里,有n个城市。编号为1,2,3,…,n。这个国家的政府修建了m条双向道路,每条道路连接着两个城市。政府规定从城市S到城市T需要收取的过路费为所经过城市之间道路长度的最大值。如:A到B长度为2,B到C长度为3,那么开车从A经过B到C需要上交的过路费为3。
佳佳是个做生意的人,需要经常开车从任意一个城市到另外一个城市,因此他需要频繁地上交过路费,由于忙于做生意,所以他无时间来寻找交过路费最低的行驶路线。然而,当他交的过路费越多他的心情就变得越糟糕。作为秘书的你,需要每次根据老板的起止城市,提供给他从开始城市到达目的城市,最少需要上交多少过路费。
Input
第一行是两个整数n 和m,分别表示城市的个数以及道路的条数。
接下来m行,每行包含三个整数 a,b,w(1≤a,b≤n,0≤w≤10^9),表示a与b之间有一条长度为w的道路。
接着有一行为一个整数q,表示佳佳发出的询问个数。
再接下来q行,每一行包含两个整数S,T(1≤S,T≤n,S≠T), 表示开始城市S和目的城市T。
Output
输出文件共q行,每行一个整数,分别表示每个询问需要上交的最少过路费用。输入数据保证所有的城市都是连通的。
Sample Input
4 5 1 2 10 1 3 20 1 4 100 2 4 30 3 4 10 2 1 4 4 1
Sample Output
20 20
HINT
对于30%的数据,满足1≤ n≤1000,1≤m≤10000,1≤q≤100;
对于50%的数据,满足1≤ n≤10000,1≤m≤10000,1≤q≤10000;
对于100%的数据,满足1≤ n≤10000,1≤m≤100000,1≤q≤10000;
题解:
和NOIP 2013 货车运输的这道题很像。
一开始的思路是最小生成树+树剖。WA了%64。蒟蒻太菜了。
一直以为是思路的锅。但是最后发现思路并没有问题。最小生成树既然能够保证全局边权和最小,那么就一定能够保证路径上的最长边最短。这个特点是最小生成树的定义能推出的,否则就会自相矛盾。
后来发现是边转点的锅。因为树剖要把边权转为点权,我们在处理这种问题的时候经常会把边权转为深度较深的节点的点权,这样能保证唯一映射,根节点的点权为0。但是在查询的时候,当查到最后,x,y跳到同一条链上的时候,就不能直接query(1,1,n,id[y],id[x]),因为那样的话就会多加一条边权。
所以我们变成query(1,1,n,id[y]+1,id[x]),即可保证正确性。
所以有AC代码:
#include<cstdio>
#include<algorithm>
#define lson pos<<1
#define rson pos<<1|1
using namespace std;
const int maxm=1e5+10;
const int maxn=1e4+10;
int n,m,cnt,q,num;
int f[maxn];
int tot,to[maxn<<1],nxt[maxn<<1],head[maxn],val[maxn<<1];
int deep[maxn],fa[maxn],size[maxn],son[maxn],top[maxn],id[maxn],w[maxn],a[maxn];
int tree[maxn<<2];
struct node
{
int x,y,z;
}e[maxm];
bool cmp(node a,node b)
{
return a.z<b.z;
}
int find(int x)
{
if(x==f[x])
return x;
return f[x]=find(f[x]);
}
void add(int x,int y,int z)
{
to[++tot]=y;
nxt[tot]=head[x];
val[tot]=z;
head[x]=tot;
}
void dfs1(int x,int from)
{
deep[x]=deep[from]+1;
fa[x]=from;
size[x]=1;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==from)
continue;
a[y]=val[i];
dfs1(y,x);
size[x]+=size[y];
if(!son[x]||size[y]>size[son[x]])
son[x]=y;
}
}
void dfs2(int x,int t)
{
top[x]=t;
id[x]=++num;
w[num]=a[x];
if(!son[x])
return;
dfs2(son[x],t);
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa[x]||y==son[x])
continue;
dfs2(y,y);
}
}
void build(int pos,int l,int r)
{
int mid=(l+r)>>1;
if(l==r)
{
tree[pos]=w[l];
return;
}
build(lson,l,mid);
build(rson,mid+1,r);
tree[pos]=max(tree[lson],tree[rson]);
}
int query(int pos,int l,int r,int x,int y)
{
int ret=0;
int mid=(l+r)>>1;
if(x<=l && r<=y)
return tree[pos];
if(x<=mid)
ret=max(ret,query(lson,l,mid,x,y));
if(y>mid)
ret=max(ret,query(rson,mid+1,r,x,y));
return ret;
}
int q1(int x,int y)
{
int ret=0;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
swap(x,y);
ret=max(ret,query(1,1,n,id[top[x]],id[x]));
x=fa[top[x]];
}
if(deep[x]<deep[y])
swap(x,y);
ret=max(ret,query(1,1,n,id[y]+1,id[x]));
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
sort(e+1,e+m+1,cmp);
for(int i=1;i<=n;i++)
f[i]=i;
for(int i=1;i<=m;i++)
{
int fx=find(e[i].x);
int fy=find(e[i].y);
if(fx!=fy)
{
f[fx]=fy;
cnt++;
add(e[i].x,e[i].y,e[i].z);
add(e[i].y,e[i].x,e[i].z);
}
if(cnt==n-1)
break;
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
scanf("%d",&q);
while(q--)
{
int u,v;
scanf("%d%d",&u,&v);
printf("%d
",q1(u,v));
}
return 0;
}