1 条题解

  • 0
    @ 2026-8-18 21:58:31

    C134 线段树分治+并查集 P5227 [AHOI2013] 连通图

    // 线段树分治 O(nlognlogn)
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    
    #define int long long
    #define ls (u<<1)
    #define rs (u<<1|1)
    #define mid (l+r>>1)
    const int N=100005;
    int n,m,k;
    int p[N],high[N],siz[N],top;
    pair<int,int>e[N<<1]; //存边
    vector<int>del[N<<1]; //边i消失的时刻
    vector<int>tr[N<<2];  //线段树节点
    struct node{
      int x,y,hy;
    }st[N<<1]; //用栈记录边的端点的合并信息
    
    void insert(int u,int l,int r,int L,int R,int i){
      if(L<=l&&r<=R) return tr[u].push_back(i);
      if(L<=mid) insert(ls,l,mid,L,R,i);
      if(R>mid) insert(rs,mid+1,r,L,R,i);
    }
    int find(int x){ //查找根
      return p[x]==x?x:find(p[x]);
    }
    void merge(int x,int y){ //合并集合
      x=find(x),y=find(y);
      if(x==y) return;
      if(high[x]>high[y]) swap(x,y);
      st[++top]={x,y,high[y]};
      p[x]=y; //x连向y
      high[y]+=(high[y]==high[x]);
      siz[y]+=siz[x]; //累加连通块的大小
    }
    void solve(int u,int l,int r){
      int now=top;
      //合并当前区间出现的边
      for(auto i:tr[u])
        merge(e[i].first,e[i].second);
      //判断去掉r时刻集合中的边后图是否联通
      if(l==r) siz[find(1)]==n?
        puts("Connected"):puts("Disconnected");
      else solve(ls,l,mid),solve(rs,mid+1,r);
      
      while(top>now){ //撤销合并
        node s=st[top--];
        p[s.x]=s.x;
        high[s.y]=s.hy;
        siz[s.y]-=siz[s.x];
      }
    }
    signed main(){
      scanf("%lld%lld",&n,&m);
      for(int i=1;i<=n;++i) p[i]=i,siz[i]=1;
      for(int i=1,x,y;i<=m;++i){
        scanf("%lld%lld",&x,&y);
        e[i].first=x,e[i].second=y;
        del[i].push_back(0);
      }
      scanf("%lld",&k);
      for(int i=1,c,j;i<=k;++i){ //k个时刻
        scanf("%lld",&c); //删c条边
        while(c--){
          scanf("%lld",&j);
          del[j].push_back(i); //边j消失的时刻
        }
      }
      for(int i=1;i<=m;++i){
        del[i].push_back(k+1);
        for(int j=0;j<del[i].size()-1;++j)
          if(del[i][j+1]-del[i][j]>1)
            insert(1,1,k,del[i][j]+1,del[i][j+1]-1,i);
            //边i出现的时间[del[i][j]+1,del[i][j+1]-1]
      }
      solve(1,1,k);
    }
    
    • 1

    C134【线段树分治+并查集】[AHOI2013] 连通图

    信息

    ID
    4902
    时间
    2000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    2
    已通过
    2
    上传者