比较好理解,相当于重建了一个二叉树,所有的父亲节点都为原来图中的边,儿子节点为点。
重构树就可以利用lca求两点间的最大(或者最小)边权以及一些树上操作。
较为简单的应用,需要用线段树来维护信息。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6;
int n,m,q;
int f[N][40],fa[N],tme[N];
int ls[N],rs[N],dis[N];
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int dep[N];
void dfs(int u,int fat)
{
dep[u]=dep[fat]+1;
f[u][0]=fat;
for(int i=1;i<=30;i++) f[u][i]=f[f[u][i-1]][i-1];
if(ls[u]!=0) dfs(ls[u],u);
if(rs[u]!=0) dfs(rs[u],u);
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=30;i>=0;i--)
{
if(dep[y]<=dep[f[x][i]])
{
x=f[x][i];
}
}
if(x==y) return x;
for(int i=30;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
#define lson (rt<<1)
#define rson (rt<<1|1)
void pushup(int rt)
{
dis[rt]=lca(dis[lson],dis[rson]);
}
void build(int rt,int l,int r)
{
if(l==r)
{
dis[rt]=l;
return ;
}
int mid=(l+r)>>1;
build(lson,l,mid); build(rson,mid+1,r);
pushup(rt);
}
int query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return dis[rt];
int mid=(l+r)>>1;
int ans=0;
if(L<=mid) ans=query(lson,l,mid,L,R);
if(R>mid) ans= ans==0?query(rson,mid+1,r,L,R):lca(ans,query(rson,mid+1,r,L,R));
return ans;
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n*2-1;i++) fa[i]=i;
for(int i=1;i<=n*2-1;i++) ls[i]=rs[i]=tme[i]=0;
int cnt=n;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
int fx=find(x),fy=find(y);
if(fx!=fy)
{
int u=++cnt;
tme[u]=i;
ls[u]=fx;
rs[u]=fy;
fa[fx]=fa[fy]=u;
}
}
dfs(cnt,0);
build(1,1,n);
for(int i=1;i<=q;i++)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",tme[query(1,1,n,l,r)]);
}
}