1. 程式人生 > 其它 >【RuoYi-Vue】RuoYi-Vue新增子模組

【RuoYi-Vue】RuoYi-Vue新增子模組

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");
    }
}

一道考試題的題解