kruskal重构树模板题
首先有三个等价的性质 我不会证!
图上任意两点的所有路径最大权值的最小值=最小生成树上任意路径的最大值=kruskal树上的lca.
就像不会sam一样 不过这个记着就行.
那么原问题就是按边的编号作为权值,查询两两之间的lca的val,最后用一个可以维护区间最值的数据结构得到答案.
code:
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
const int M=20;
int cnt=0;
int fa[N],ch[N][2],f[N][M],val[N],dep[N];
int n,m,q;
int w[N],mx[N<<1];
struct node{
int u,v,w;
}a[N];
void init()
{
for(int i=0;i<=(n<<1);i++) fa[i]=i;
}
int dsu(int u)
{
if(u==fa[u]) return u;
else return fa[u]=dsu(fa[u]);
}
void kruskal()
{
for(int i=1;i<=m;i++)
{
int x=dsu(a[i].u);int y=dsu(a[i].v);
if(x==y) continue;
ch[++cnt][0]=x,ch[cnt][1]=y;
fa[x]=fa[y]=f[x][0]=f[y][0]=cnt;
val[cnt]=a[i].w;
}
for(int i=1;i<20;i++)
for(int j=1;j<=cnt;j++)
f[j][i]=f[f[j][i-1]][i-1];
}
void dfs(int u)
{
dep[u]=dep[f[u][0]]+1;
if(ch[u][0]) dfs(ch[u][0]);
if(ch[u][1]) dfs(ch[u][1]);
}
int lca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
for(int i=19;i>=0;i--)
{
if(dep[f[u][i]]>=dep[v]) u=f[u][i];
}
if(u==v) return u;
for(int i=19;i>=0;i--)
{
if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
}
return f[u][0];
}
void build(int u,int l,int r)
{
if(l==r)
{
mx[u]=w[l];
return;
}
int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
mx[u]=max(mx[u<<1],mx[u<<1|1]);
}
int qry(int u,int l,int r,int L,int R)
{
if(R<L) return 0;
if(R<l||L>r) return 0;
if(L<=l&&r<=R) return mx[u];
int mid=(l+r)>>1;
return max(qry(u<<1,l,mid,L,R),qry(u<<1|1,mid+1,r,L,R));
}
void run()
{
scanf("%d%d%d",&n,&m,&q);
cnt=n;
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
a[i]={u,v,i};
}
init();
kruskal();
dfs(cnt);
for(int i=1;i<n;i++)
w[i]=val[lca(i,i+1)];
build(1,1,n-1);
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d ",qry(1,1,n-1,l,r-1));
}
printf("\n");
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
run();
}
return 0;
}