【BZOJ 3237】连通图(线段树分治)

题目链接

题意

给出一张图,每次询问删去图中一些边后(边数不超过4)图的连通性

题解

首先删边是不好处理的,于是我们要把没有删掉的边加入

考虑到被删掉边只有4条,那么每一次加边其实有很多是加重了的,可以看出是线段树分治了

每一条边影响的询问被分为很多段

通过标记永久化和树上dfs栈序撤销操作来批量处理与询问有关的修改

加边等价于修改操作

P.S:跑得很慢.....

代码:

#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int read()
{
    int x=0;char ch=getchar();int t=1;
    for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=-1;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
    return x*t;
}
const int N=2e5+10;
int n,m,K;
#define ls (now<<1)
#define rs (now<<1|1)
namespace segment_tree{
    struct edge{int u,v;}a[N];
    struct set{int fa;int size;int dep;}F[N];
    vector<int> V[21*N];
    int fir[N];//每一条边当前应该添加的起始位置,断点就是删掉它的询问
    inline int find(int x){return (F[x].fa==x)? x:find(F[x].fa);}
    void insert(int now,int l,int r,int L,int R,int x){
        if(l>=L&&r<=R){V[now].push_back(x);return;}
        register int mid=l+r>>1;
        if(mid>=L) insert(ls,l,mid,L,R,x);
        if(mid1,r,L,R,x);
        return;
    }
    void init()
    {
        register int u,v;
        for(register int i=1;i<=n;++i) F[i]=(set){i,1,1};
        for(register int i=1;i<=m;++i){u=read();v=read();a[i]=(edge){u,v};fir[i]=1;}
        K=read();
        for(register int i=1;i<=K;++i)
        {
            register int num=read();
            for(register int j=1;j<=num;++j){
                u=read();
                if(fir[u]<=i-1) insert(1,1,K,fir[u],i-1,u);
                fir[u]=i+1;
            }
        }
        for(register int i=1;i<=m;++i) if(fir[i]<=K) insert(1,1,K,fir[i],K,i);
        return;
    }
    stack< set > S;int top=0;
    void segment_Div(int now,int l,int r){
        register int tp1=top;
        register int mid=l+r>>1;
        for(register int i=0;iregister int e=V[now][i];
            register int fx=find(a[e].u),fy=find(a[e].v);
            if(fx==fy) continue;
            if(F[fx].dep>F[fy].dep) swap(fx,fy);
            top+=2;
            S.push(F[fx]);S.push(F[fy]);
            F[fx].fa=fy;F[fy].dep=max(F[fy].dep,F[fx].dep+1);F[fy].size+=F[fx].size;
        }
        if(l==r) {register int fx=find(1);if(F[fx].size==n) puts("Connected");else puts("Disconnected");}
        else segment_Div(ls,l,mid),segment_Div(rs,mid+1,r);
        while(top!=tp1) {--top;register set T=S.top();S.pop();F[T.fa]=T;}
        return;
    }
}
int main()
{
    n=read();m=read();
    segment_tree::init();
    segment_tree::segment_Div(1,1,K);
    return 0;
}

你可能感兴趣的:(======题解======,并查集,线段树分治,——分治——)