CodeForces - 1706E Qpwoeirut and Vertices (kruskal重构树+倍增+可持久化线段树合并)

题目链接
题意:给定一个无向图,每次询问将[l,r]区间上的点全部联通需要用到至少前几条边
挺套路化的题,以边的顺序作为权值构造最小生成树的kruskal重构树,每个结点上记录边的权值,并存储一棵线段树记录该连通块下每个区间上有多少点,父结点由子结点合并而成(我用了可持久化合并,因为可以在线查询)。对于询问(l,r),从结点l出发,用倍增找到第一个sum(l,r)=r-l+1的父结点,该结点的权值就是答案。
复杂度\(O(nlogn+qlog^2n)\)

#include <bits/stdc++.h>
using namespace std;
const int N=3e5+10;
#define l(u) ch[u][0]
#define r(u) ch[u][1]
#define mid ((l+r)>>1)

namespace SegTree {
int n,tot,ch[N*20][2],sum[N*20];
void init(int _n) {n=_n,tot=0;}
int newnode() {int u=++tot; l(u)=r(u)=sum[u]=0; return u;}
void add(int& w,int u,int x,int l=1,int r=n) {
    w=newnode();
    sum[w]=sum[u]+1;
    if(l==r)return;
    if(x<=mid)add(l(w),l(u),x,l,mid),r(w)=r(u);
    else add(r(w),r(u),x,mid+1,r),l(w)=l(u);
}
void mg(int& w,int u,int v,int l=1,int r=n) {
    if(!u||!v) {w=u|v; return;}
    w=newnode();
    sum[w]=sum[u]+sum[v];
    mg(l(w),l(u),l(v),l,mid),mg(r(w),r(u),r(v),mid+1,r);
}
int qry(int u,int L,int R,int l=1,int r=n) {
    if(l>=L&&r<=R)return sum[u];
    if(l>R||r<L)return 0;
    return qry(l(u),L,R,l,mid)+qry(r(u),L,R,mid+1,r);
}
};

int n,m,Q,Fa[N],fa[N],F[N][20],C[N],tot,rt[N];
struct E {
    int u,v,c;
    bool operator<(const E& b)const {return c<b.c;}
} e[N];
int fd(int x) {return Fa[x]?Fa[x]=fd(Fa[x]):x;}
void kruskal() {
    SegTree::init(n+m);
    sort(e+1,e+1+m);
    tot=n;
    for(int i=1; i<=n+m; ++i)Fa[i]=C[i]=rt[i]=0,fa[i]=i;
    for(int i=1; i<=n; ++i)SegTree::add(rt[i],rt[i],i);
    for(int i=1; i<=m; ++i) {
        int u=e[i].u,v=e[i].v,c=e[i].c;
        int fx=fd(u),fy=fd(v);
        if(fx==fy)continue;
        int w=++tot;
        C[w]=c;
        Fa[fx]=Fa[fy]=w;
        fa[fx]=fa[fy]=w;
        SegTree::mg(rt[w],rt[fx],rt[fy]);
    }
}
void build_da() {
    for(int i=1; i<=tot; ++i)F[i][0]=fa[i];
    for(int j=1; j<20; ++j)
        for(int i=1; i<=tot; ++i)
            F[i][j]=F[F[i][j-1]][j-1];
}
int qry(int l,int r) {
    if(l==r)return 0;
    int u=l;
    for(int j=19; j>=0; --j)
        if(SegTree::qry(rt[F[u][j]],l,r)<r-l+1)u=F[u][j];
    return C[F[u][0]];
}
int main() {
    int T;
    for(scanf("%d",&T); T--;) {
        scanf("%d%d%d",&n,&m,&Q);
        for(int i=1; i<=m; ++i)scanf("%d%d",&e[i].u,&e[i].v),e[i].c=i;
        kruskal();
        build_da();
        for(int i=0; i<Q; ++i) {
            int l,r;
            scanf("%d%d",&l,&r);
            if(i)printf(" ");
            printf("%d",qry(l,r));
        }
        puts("");
    }
    return 0;
}


posted @ 2022-07-22 16:37  jrltx  阅读(87)  评论(0编辑  收藏  举报