kruskal 重构树
kruskal 重构树
这个东西在很早之前考试的时候考过一次,那次匆匆忙忙没有学好,现在重学一遍
首先明确,重构树一定满足是一个二叉堆,也就是说,这个树是有单调性的
所以我们可以用这玩意解决一些单调性的问题
重构的是边权,把所有边都化成点,我们重构完之后可以找到两点之间的路径最大最小权值
重构树的子树权值都比当前点的权值小/大,所以我们可以用一些建立在\(dfs\)序上的东西来解决问题
整体更改子树答案之类的
重构树中所有的叶子节点都是原树上的点,其余的都是边
例题
这个我们建立两颗重构树
一开始确实没有啥思路,即使知道是\(kruskal\)重构树,也不知道边权是啥
但是发现我们只需要满足点权大于或者小于某个值就好了
那我们就以边的两个端点的最大值或者最小值作为边权来连边,这样保证了可以到达子树内任意一点
1、以两端点最大值作为边权,最小生成树,因为我们要满足小于某个值的都可以到,大的满足小的就满足
2、以两端点最小值作为边权,最大生成树,满足大于某个值的都可以到,所以小的满足了大的一定满足
然后我们倍增上去看看最远到哪
于是就要判断子树有无交集,\(dfs\)序+主席树
以第一颗树的序为历史版本,第二颗树的为权值......
code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
int s=0,t=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
return s*t;
}
const int inf=0x3f3f3f3f;
const int N=4e5+5;
int n,m,q;
struct E{int x,y;}e[N*4];
bool com1(E a,E b){return max(a.x,a.y)<max(b.x,b.y);}
bool com2(E a,E b){return min(a.x,a.y)>min(b.x,b.y);}
struct K{
int to[N],nxt[N],head[N],rp;
int fa[N][21],dfn[N],dfm[N],cnt;
int val[N],idf[N];
void add_edg(int x,int y){
to[++rp]=y;
nxt[rp]=head[x];
head[x]=rp;
}
void dfs(int x,int f){
fa[x][0]=f;
fo(i,1,20)fa[x][i]=fa[fa[x][i-1]][i-1];
if(x>n)dfn[x]=cnt+1;
else dfn[x]=++cnt,idf[cnt]=x;
for(int i=head[x];i;i=nxt[i])dfs(to[i],x);
dfm[x]=cnt;
}
int fai[N];
int find(int x){return fai[x]==x?x:fai[x]=find(fai[x]);}
void kruskal(int typ){
int cnt=n;
fo(i,1,n)fai[i]=val[i]=i;
fo(i,1,m){
int fx=find(e[i].x),fy=find(e[i].y);
if(fx==fy)continue;
++cnt;fai[cnt]=cnt;
if(typ)val[cnt]=min(e[i].x,e[i].y);
else val[cnt]=max(e[i].x,e[i].y);
add_edg(cnt,fx);add_edg(cnt,fy);
fai[fx]=cnt;fai[fy]=cnt;
}
dfs(cnt,0);
}
}a,b;
int rt[N];
struct ZXS{
struct POT{
int sum,ls,rs;
}tr[N*35];
int seg;
void ins(int pr,int &x,int l,int r,int pos){
x=++seg;tr[x]=tr[pr];tr[x].sum++;
if(l==r)return ;
int mid=l+r>>1;
if(pos<=mid)ins(tr[pr].ls,tr[x].ls,l,mid,pos);
else ins(tr[pr].rs,tr[x].rs,mid+1,r,pos);
return ;
}
int query(int pr,int x,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return tr[x].sum-tr[pr].sum;
int mid=l+r>>1,ret=0;
if(ql<=mid)ret+=query(tr[pr].ls,tr[x].ls,l,mid,ql,qr);
if(qr>mid)ret+=query(tr[pr].rs,tr[x].rs,mid+1,r,ql,qr);
return ret;
}
}zxs;
signed main(){
n=read();m=read();q=read();
fo(i,1,m)e[i].x=read()+1,e[i].y=read()+1;
sort(e+1,e+m+1,com1);a.val[0]=inf;
a.kruskal(0);
sort(e+1,e+m+1,com2);b.val[0]=-inf;
b.kruskal(1);
fo(i,1,n)zxs.ins(rt[i-1],rt[i],1,n,b.dfn[a.idf[i]]);
while(q--){
int s=read()+1,t=read()+1,l=read()+1,r=read()+1;
fu(i,20,0)if(a.val[a.fa[t][i]]<=r)t=a.fa[t][i];
fu(i,20,0)if(b.val[b.fa[s][i]]>=l)s=b.fa[s][i];
// cout<<t<<" "<<s<<endl;
if(zxs.query(rt[a.dfn[t]-1],rt[a.dfm[t]],1,n,b.dfn[s],b.dfm[s]))puts("1");
else puts("0");
}
}
QQ:2953174821