kruskal 重构树

kruskal 重构树

这个东西在很早之前考试的时候考过一次,那次匆匆忙忙没有学好,现在重学一遍

首先明确,重构树一定满足是一个二叉堆,也就是说,这个树是有单调性的

所以我们可以用这玩意解决一些单调性的问题

重构的是边权,把所有边都化成点,我们重构完之后可以找到两点之间的路径最大最小权值

重构树的子树权值都比当前点的权值小/大,所以我们可以用一些建立在\(dfs\)序上的东西来解决问题

整体更改子树答案之类的

重构树中所有的叶子节点都是原树上的点,其余的都是边

例题

Luogu4899 IOI2018 werewolf狼人

这个我们建立两颗重构树

一开始确实没有啥思路,即使知道是\(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");
    }
}

一道考试题的题解

posted @ 2021-12-15 20:01  fengwu2005  阅读(48)  评论(0编辑  收藏  举报