problem
Description
给你N个点的无向连通图,图中有M条边,第j条边的长度为: d_j.
现在有 K个询问。
每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?
Input
文件名为heatwave.in
第一行: N, M, K。
第2..M+1行: 三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N). 表示X与Y之间有一条长度为D的边。
第M+2..M+K+1行: 每行两个整数A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?
Output
对每个询问,输出最长的边最小值是多少。
Sample Input
6 6 8
1 2 5
2 3 4
3 4 3
1 4 8
2 5 7
4 6 2
1 2
1 3
1 4
2 3
2 4
5 1
6 2
6 1
Sample Output
5
5
5
4
4
7
4
5
Data Constraint
50% 1<=N,M<=3000 其中30% K<=5000
100% 1 <= N <= 15,000 1 <= M <= 30,000 1 <= d_j <= 1,000,000,000 1 <= K <= 20,000
Hint
analysis
既然题目要求两点间最长边的最小值,那么我们就把这幅图的MST先求出来
这样两点间一定联通且满足两点间最长边最小(没有为什么自己想一想因为这点比较明显)
MST用kruskal求,比较基础,我就当你会了
求完MST之后把整棵树遍历一次,求出每个点的深度
树上倍增
(这题的JZ数据buff加成导致O(n)的LCA乱搞也能AC……然后嘿嘿嘿)
然后打了个奇丑无比的倍增
维护两个数组anc[i,j]和dis[i,j]分别表示i节点的2^j号祖先和i节点的与第2^j号祖先之间的路径最小值
接下来就和普通倍增没什么区别了,先把两个点调至同一深度,然后一起往上跳,跳的过程中记录答案
时间复杂度O(mlog2m+nlog2n+qlog2n)
树链剖分
树剖当然也能做啦!
把树剖分完以后,用线段树维护整一条重链的max值
树剖求LCA过程中查询线段树记录最大值
对于树剖来说这就是一道模板题
时间复杂度O(n+qlog22n)
code
树上倍增code(50+ms)
var
a,edge:array[0..15000]of array of longint;
anc,dis:array[0..15000,0..15]of longint;
b:array[0..30000,0..3]of longint;
depth,father:array[0..15000]of longint;
n,m,q,i,j,x,y:longint;
function max(x,y:longint):longint;
begin
if x>y then exit(x);
exit(y);
end;
procedure swap(var x,y:longint);
var
z:longint;
begin
z:=x;
x:=y;
y:=z;
end;
procedure qsort(l,r:longint);
var
i,j,mid:longint;
begin
i:=l;
j:=r;
mid:=b[(l+r)div 2,3];
repeat
while b[i,3]<mid do inc(i);
while b[j,3]>mid do dec(j);
if i<=j then
begin
b[0]:=b[i];
b[i]:=b[j];
b[j]:=b[0];
inc(i);
dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
function getfather(x:longint):longint;
begin
if father[x]=x then exit(x);
father[x]:=getfather(father[x]);
exit(father[x]);
end;
procedure dfs(x,y:longint);
var
i:longint;
begin
for i:=1 to a[x,0] do
if a[x,i]<>y then
begin
anc[a[x,i],0]:=x;
depth[a[x,i]]:=depth[x]+1;
dis[a[x,i],0]:=edge[x,i];
dfs(a[x,i],x);
end;
end;
function lca(x,y:longint):longint;
var
k:longint;
begin
lca:=0;
if depth[x]<depth[y] then swap(x,y);
k:=trunc(ln(depth[x]-depth[y]+1)/ln(2));
while k>=0 do
begin
if depth[anc[x,k]]>depth[y] then
begin
lca:=max(lca,dis[x,k]);
x:=anc[x,k];
end;
dec(k);
end;
if depth[x]<>depth[y] then
begin
lca:=max(lca,dis[x,0]);
x:=anc[x,0];
end;
k:=trunc(ln(depth[x])/ln(2));
while k>=0 do
begin
if anc[x,k]<>anc[y,k] then
begin
lca:=max(max(lca,dis[x,k]),dis[y,k]);
x:=anc[x,k];
y:=anc[y,k];
end;
dec(k);
end;
if x=y then exit(lca);
exit(max(lca,max(dis[x,0],dis[y,0])));
end;
begin
readln(n,m,q);
for i:=1 to n do
begin
father[i]:=i;
setlength(a[i],1);
a[i,0]:=0;
setlength(edge[i],1);
edge[i,0]:=0;
end;
for i:=1 to m do
begin
for j:=1 to 3 do read(b[i,j]);
readln;
end;
qsort(1,m);
for i:=1 to m do
begin
x:=b[i,1];
y:=b[i,2];
if getfather(x)<>getfather(y)then
begin
father[getfather(x)]:=getfather(y);
inc(a[x,0]);
setlength(a[x],a[x,0]+1);
a[x,a[x,0]]:=y;
inc(edge[x,0]);
setlength(edge[x],edge[x,0]+1);
edge[x,a[x,0]]:=b[i,3];
inc(a[y,0]);
setlength(a[y],a[y,0]+1);
a[y,a[y,0]]:=x;
inc(edge[y,0]);
setlength(edge[y],edge[y,0]+1);
edge[y,a[y,0]]:=b[i,3];
end;
end;
depth[1]:=1;
dfs(1,0);
for j:=1 to trunc(ln(n)/ln(2)) do
for i:=1 to n do
begin
anc[i,j]:=anc[anc[i,j-1],j-1];
dis[i,j]:=max(dis[i,j-1],dis[anc[i,j-1],j-1]);
end;
for i:=1 to q do
begin
readln(x,y);
writeln(lca(x,y));
end;
end.
var
b,c,next,last,father,size:array[0..80000]of longint;
anc,dis:array[0..15000,0..16]of longint;
a:array[0..30000,1..3] of longint;
n,m,i,j,k,x,y,tot:longint;
procedure swap(var x,y:longint);
var
z:longint;
begin
z:=x;
x:=y;
y:=z;
end;
function max(x,y:longint):longint;
begin
if x>y then exit(x);
exit(y);
end;
procedure qsort(l,r:longint);
var
i,j,mid:longint;
begin
i:=l;
j:=r;
mid:=a[(l+r)div 2,3];
repeat
while a[i,3]<mid do inc(i);
while a[j,3]>mid do dec(j);
if i<=j then
begin
a[0]:=a[i];
a[i]:=a[j];
a[j]:=a[0];
inc(i);
dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
function getfather(k:longint):longint;
begin
if father[k]=0 then exit(k);
father[k]:=getfather(father[k]);
exit(father[k]);
end;
function judge(x,y:longint):boolean;
begin
exit(getfather(x)=getfather(y));
end;
procedure insert(x,y,z:longint);
begin
inc(tot);
b[tot]:=y;
next[tot]:=last[x];
last[x]:=tot;
c[tot]:=z;
end;
procedure dfs(x,y:longint);
var
now:longint;
begin
now:=last[x];
while now<>0 do
begin
if b[now]<>y then
begin
anc[b[now],0]:=x;
size[b[now]]:=size[x]+1;
dis[b[now],0]:=c[now];
dfs(b[now],x);
end;
now:=next[now];
end;
end;
function lca(x,y:longint):longint;
var
k:longint;
begin
lca:=0;
if size[x]<size[y] then swap(x,y);
k:=trunc(ln(size[x]-size[y]+1)/ln(2));
while k>=0 do
begin
if size[anc[x,k]]>size[y] then
begin
lca:=max(lca,dis[x,k]);
x:=anc[x,k];
end;
dec(k);
end;
if size[x]<>size[y] then
begin
lca:=max(lca,dis[x,0]);
x:=anc[x,0];
end;
k:=trunc(ln(size[x])/ln(2));
while k>=0 do
begin
if anc[x,k]<>anc[y,k] then
begin
lca:=max(max(lca,dis[x,k]),dis[y,k]);
x:=anc[x,k];
y:=anc[y,k];
end;
dec(k);
end;
if x=y then exit(lca);
exit(max(lca,max(dis[x,0],dis[y,0])));
end;
begin
assign(input,'readin.pas');reset(input);
readln(n,m,k);
for i:=1 to m do readln(a[i,1],a[i,2],a[i,3]);
qsort(1,m);
for i:=1 to m do
begin
if (not judge(a[i,1],a[i,2])) then
begin
insert(a[i,1],a[i,2],a[i,3]);
insert(a[i,2],a[i,1],a[i,3]);
father[getfather(a[i,1])]:=getfather(a[i,2]);
end;
end;
size[1]:=1;
dfs(1,0);
for j:=1 to trunc(ln(n)/ln(2)) do
for i:=1 to n do
begin
anc[i,j]:=anc[anc[i,j-1],j-1];
dis[i,j]:=max(dis[i,j-1],dis[anc[i,j-1],j-1]);
end;
for i:=1 to k do
begin
readln(x,y);
writeln(lca(x,y));
end;
end.
树链剖分code(44ms)
#include<cstdio>
#include<algorithm>
#define MAXN 15001
#define INF 1000000007
using namespace std;
int last[4*MAXN],next[4*MAXN],tov[4*MAXN],dis[4*MAXN];
int to_num[4*MAXN],father[MAXN];
int n,m,k,tot,total;
struct information
{
int depth,father,size,heavy_son,top,to_tree,value;
}a[4*MAXN];
struct point
{
int mx,ans;
}tree[4*MAXN];
struct dist
{
int u,v,w;
}line[4*MAXN];
bool cmp(dist a,dist b)
{
return a.w<b.w;
}
int getfather(int x)
{
if (father[x]==0)return x;
father[x]=getfather(father[x]);
return father[x];
}
void insert(int x,int y,int z)
{
next[++tot]=last[x];
last[x]=tot;
tov[tot]=y;
dis[tot]=z;
}
void dfs1(int x,int father)
{
int mx=-1;
a[x].size=1;
for (int i=last[x];i;i=next[i])
{
int j=tov[i];
if (j!=father)
{
a[j].depth=a[x].depth+1;
a[j].father=x;
a[j].value=dis[i];
dfs1(j,x);
a[x].size+=a[j].size;
if (a[j].size>mx)
{
mx=a[j].size;
a[x].heavy_son=j;
}
}
}
}
void dfs2(int x,int father,int top)
{
if (x==0)return;
a[x].top=top;
a[x].to_tree=++total;
to_num[total]=x;
dfs2(a[x].heavy_son,x,top);
for (int i=last[x];i;i=next[i])
{
int j=tov[i];
if (j!=father && j!=a[x].heavy_son && j!=0)
{
dfs2(j,x,j);
}
}
}
void maketree(int t,int l,int r)
{
if (l==r)
{
tree[t].mx=a[to_num[l]].value;
return;
}
int mid=(l+r)/2;
maketree(t*2,l,mid);
maketree(t*2+1,mid+1,r);
tree[t].mx=max(tree[t*2].mx,tree[t*2+1].mx);
}
int tree_query_max(int t,int l,int r,int x,int y)
{
if (l==x && r==y)
{
return tree[t].mx;
}
int mid=(l+r)/2;
if (y<=mid)
{
return tree_query_max(t*2,l,mid,x,y);
}
else if (x>mid)
{
return tree_query_max(t*2+1,mid+1,r,x,y);
}
else return max(tree_query_max(t*2,l,mid,x,mid),tree_query_max(t*2+1,mid+1,r,mid+1,y));
}
int query_max(int x,int y)
{
int temp=-1;
while (a[x].top!=a[y].top)
{
if (a[a[x].top].depth>a[a[y].top].depth)
{
temp=max(temp,tree_query_max(1,1,n,a[a[x].top].to_tree,a[x].to_tree));
x=a[a[x].top].father;
}
else
{
temp=max(temp,tree_query_max(1,1,n,a[a[y].top].to_tree,a[y].to_tree));
y=a[a[y].top].father;
}
}
if (x==y)return temp;
if (a[x].depth<a[y].depth)
{
temp=max(temp,tree_query_max(1,1,n,a[a[x].heavy_son].to_tree,a[y].to_tree));
}
else
{
temp=max(temp,tree_query_max(1,1,n,a[a[y].heavy_son].to_tree,a[x].to_tree));
}
return temp;
}
int main()
{
//freopen("readin.txt","r",stdin);
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&line[i].u,&line[i].v,&line[i].w);
}
sort(line+1,line+m+1,cmp);
for (int i=1;i<=m;i++)
{
if (getfather(line[i].u)!=getfather(line[i].v))
{
father[getfather(line[i].u)]=getfather(line[i].v);
insert(line[i].u,line[i].v,line[i].w);
insert(line[i].v,line[i].u,line[i].w);
}
}
a[1].depth=1;
dfs1(1,0),dfs2(1,0,1);
maketree(1,1,n);
for (int i=1;i<=k;i++)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",query_max(x,y));
}
return 0;
}
不过其实对于随机数据的LCA,倍增没有什么意义