Kruskal 重构树
这个还是基于Kruskal最小生成树算法.
我们正常跑最小生成树,把两个点放到并查集中.
但是这个里面我们把边换成一个点权等于边权的点,然后让他与两个点链接起来.
最后就形成了Kruskal 重构树.
写这个是因为考场上的这个题,链接
考场上思路只到最小生成树,然后想不下去了,感觉与并查集维护没差别.
现在发现当时我脑子有多昏了,虽然说现在还是挺昏的.
这个题考虑要求,它说[l,r]全部相通.所以放上一个最小生成树,边权是边的编号,这个好想.
然后对这个树遍历一遍,用st表维护父亲信息与最值.
这个时候我们预处理出来l与l+1的LCA信息,因为我们区间都连续,所以直接把每个l,l+1的信息维护出来.
对这些信息放到一个新的ST表中或者线段树中维护即可.
至于Kruskal 重构树,它的意义在于打最小生成树时会发现,st表维护的信息是不固定的,你要在dfs中把上面的边值给该点.
将边权赋给st表,也不算很麻烦吧,但Kruskal 重构树更直观些.(其实没有大差别)
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define qr qr()
#define ps push_back
#define fi first
#define se second
#define pa pair<int,int>
#define ve vector
using namespace std;
const int N=4e5+200;
int dep[N],st[N<<1][24],mx[N<<1][24],ans[N],val[N<<1];
ve <int> e[N];
inline ll qr{
ll x=0;char ch=getchar();bool f=0;
while(ch>57||ch<48)f=(ch=='-')?1:0,ch=getchar();
while(ch>=48&&ch<=57)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
struct tr{
int l,r,mx;
}t[N<<2];
inline void add(int f,int t){
e[f].ps(t);
e[t].ps(f);
}
void dfs(int u,int fa,int dp){
dep[u]=dp;
for(int i=1;i<=20;++i){
st[u][i]=st[st[u][i-1]][i-1];
mx[u][i]=max(mx[st[u][i-1]][i-1],mx[u][i-1]);
}
// cout<<u<<endl;
// for(int i=0;i<=4;++i)
// cout<<mx[u][i]<<' ';
// cout<<endl;
for(auto v:e[u]){
if(v==fa)continue;
st[v][0]=u;
mx[v][0]=val[u];
dfs(v,u,dp+1);
}
}
inline int lca(int a,int b){
if(dep[a]<dep[b])swap(a,b);
int mxx=0;
for(int i=20;i>=0;--i){
if(dep[st[a][i]]>=dep[b])
mxx=max(mxx,mx[a][i]),a=st[a][i];
}if(a==b)return mxx;
for(int i=20;i>=0;--i)
if(st[a][i]!=st[b][i])
mxx=max({mxx,mx[a][i],mx[b][i]}),a=st[a][i],b=st[b][i];
return mxx;
}
void build(int rt,int l,int r){
t[rt].l=l;t[rt].r=r;
if(l==r){
t[rt].mx=ans[l];
return;
}int md=(l+r)>>1;
build(rt<<1,l,md);
build(rt<<1|1,md+1,r);
t[rt].mx=max(t[rt<<1].mx,t[rt<<1|1].mx);
}
int n,m,q,tot,fa[N];
int find(int a){
return(a==fa[a])?a:fa[a]=find(fa[a]);
}
int ask(int rt,int l,int r){
if(l>r)return 0;
if(t[rt].l>=l&&t[rt].r<=r)return t[rt].mx;
int mxx=0;
if(t[rt<<1].r>=l)mxx=ask(rt<<1,l,r);
if(t[rt<<1].r<r)mxx=max(mxx,ask(rt<<1|1,l,r));
return mxx;
}
inline void merge(int f,int t){
f=find(f),t=find(t);
fa[t]=fa[f];
}
void init(){
n=qr;m=qr;q=qr;
tot=n;
for(int i=1;i<=n;++i)fa[i]=i;
for(int i=1;i<=m;++i){
int f=qr,t=qr;
if(find(f)!=find(t)){
merge(f,t);
add(f,++tot);
add(tot,t);
val[tot]=i;
}
}
dfs(1,0,1);
for(int i=1;i<n;++i)
ans[i]=lca(i,i+1);
build(1,1,n);
while(q--){
int a=qr,b=qr;
cout<<ask(1,a,b-1)<<endl;
}
}
int main(){
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
init();
return 0;
}
https://www.cnblogs.com/shining-like-stars