又是最小生成树+树链剖分的经典组合题。
还有一种做法,就是大白书上的LCA做法。
树链剖分就是将线段树应用在树上。
LCA有点像把ST表应用在树上。只是有点像而已。毕竟LCA是O(logn)回答,而ST表是O(1)回答。
写LCA时因为不够理解算法所以有个地方写错了WA了好久。
代码
#include<bits/stdc++.h>
#define ls (now<<1)
#define rs (ls|1)
using namespace std;
const int maxn = 50010;
const int maxm = 100010;
int n,m;
vector<int>G[maxn];
vector<int>W[maxn];
int u[maxm],v[maxm],w[maxm];
int r[maxm];
int cmp(int i,int j){return w[i]<w[j];}
int fa[maxn];
int f(int x){return fa[x]==x?x:fa[x]=f(fa[x]);}
void Kruskal()
{
for(int i=0;i<n;i++) fa[i]=i,G[i].clear(),W[i].clear();
for(int i=0;i<m;i++) r[i]=i;
sort(r,r+m,cmp);
for(int i=0;i<m;i++)
{
int e=r[i];
int x=f(u[e]);
int y=f(v[e]);
if(x!=y)
{
fa[x]=y;
G[u[e]].push_back(v[e]);
G[v[e]].push_back(u[e]);
W[u[e]].push_back(w[e]);
W[v[e]].push_back(w[e]);
}
}
}
int tree[maxn<<2];
void add(int l,int r,int now,int pos,int val)
{
if(l==r)
{
tree[now]=val;
return;
}
int m=l+(r-l)/2;
if(pos<=m) add(l,m,ls,pos,val);
else add(m+1,r,rs,pos,val);
tree[now]=max(tree[ls],tree[rs]);
}
int siz[maxn],fat[maxn],son[maxn],dep[maxn];
void dfs1(int u,int f,int d)
{
siz[u]=1;
fat[u]=f;
son[u]=-1;
dep[u]=d;
for(unsigned int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v==f) continue;
dfs1(v,u,d+1);
siz[u]+=siz[v];
if(son[u]==-1||siz[son[u]]<siz[v]) son[u]=v;
}
}
int tim,tid[maxn],top[maxn],rnk[maxn];
void dfs2(int u,int tp)
{
tid[u]=++tim;
rnk[tid[u]]=u;
top[u]=tp;
if(son[u]==-1) return;
dfs2(son[u],tp);
for(unsigned int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v==fat[u]) continue;
if(v==son[u])
{
add(1,n,1,tid[v],W[u][i]);
continue;
}
dfs2(v,v);
add(1,n,1,tid[v],W[u][i]);
}
}
int qry(int l,int r,int now,int ql,int qr)
{
if(ql<=l&&r<=qr) return tree[now];
if(ql>r||qr<l) return 0;
int m=l+(r-l)/2;
return max(qry(l,m,ls,ql,qr),qry(m+1,r,rs,ql,qr));
}
int RMQ(int x,int y)
{
int tpx=top[x],tpy=top[y];
int ret=0;
while(x!=y)
{
if(tpx!=tpy)
{
if(dep[tpx]<dep[tpy])
{
swap(x,y);
swap(tpx,tpy);
}
ret=max(ret,qry(1,n,1,tid[tpx],tid[x]));
x=fat[tpx];tpx=top[x];
}
else
{
if(dep[x]<dep[y])
{
swap(x,y);
swap(tpx,tpy);
}
ret=max(ret,qry(1,n,1,tid[y]+1,tid[x]));
return ret;
}
}
return ret;
}
int flag;
int main()
{
while(scanf("%d %d",&n,&m)==2)
{
if(flag) puts("");
flag=1;
for(int i=0;i<m;i++)
scanf("%d %d %d",u+i,v+i,w+i),
u[i]--,v[i]--;
Kruskal();
add(1,n,1,1,0);
dfs1(0,-1,0);
tim=0;
dfs2(0,0);
int q,s,t;
scanf("%d",&q);
while(q--)
{
scanf("%d %d",&s,&t);
printf("%d\n",RMQ(s-1,t-1));
}
}
return 0;
}