分治-线段树分治

把操作拆成若干作用在不同时间段的操作,时间段划分按线段树划分方式,因此才叫线段树分治。

以下就以Bzoj4025为例题吧。

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int N=1e5+5;
const int M=2e5+5;
const int TM=1e5+5;
const int S=2*TM;

struct edg{
    int u,v;
};
vector<edg>x[S];
int c[S][2],in[S][2];
int rt,cnt;

int sk[M],tp;

bool ans[TM];

int uf[N],sz[N],lz[N];

int bld(int l,int r){
    int v=++cnt,mid=(l+r)>>1;
    in[v][0]=l,
    in[v][1]=r;
    if(l==r)
        return v;
    c[v][0]=bld(l,mid),
    c[v][1]=bld(mid+1,r);
    return v;
}

void add(int v,edg e,int l,int r){
    if(l<=in[v][0]&&in[v][1]<=r){
        x[v].push_back(e);
        return;
    }
    if(l<=in[c[v][0]][1])
        add(c[v][0],e,l,r);
    if(in[c[v][1]][0]<=r)
        add(c[v][1],e,l,r);
}

int gtf(int v,int &l){
    if(uf[v]==v){
        l=lz[v];
        return v;
    }
    int f=gtf(uf[v],l);
    l^=lz[v];
    return f;
}

int mrg(edg e,int &s){
    int fu,fv,lu,lv;
    fu=gtf(e.u,lu),
    fv=gtf(e.v,lv);
    if(fu==fv)
        return lu^lv^1;
    if(sz[fu]<sz[fv])
        swap(fu,fv),
        swap(lu,lv);
    uf[fv]=fu;
    sz[fu]+=sz[fv];
    lz[fv]=lu^lv^1;
    sk[++tp]=fv;
    ++s;
    return 0;
}

void dlt(){
    int u=sk[tp],f,l;
    --tp;
    f=gtf(u,l);
    sz[f]-=sz[u];
    uf[u]=u;
    lz[u]=0;
}

void dfs(int v,int b){
    int i,t=b,s=0;
    for(i=0;i<x[v].size()&&t;i++)
        t^=mrg(x[v][i],s);
    if(in[v][0]==in[v][1])
        ans[in[v][0]]=t;
    else
        dfs(c[v][0],t),
        dfs(c[v][1],t);
    for(i=1;i<=s;i++)
        dlt();
}

int main()
{
    int n,m,t,i,u,v,b,e;
    scanf("%d%d%d",&n,&m,&t);
    rt=bld(1,t);
    for(i=1;i<=m;i++){
        scanf("%d%d%d%d",&u,&v,&b,&e);
        if(b<e)
            add(rt,(edg){u,v},b+1,e);
    }
    for(i=1;i<=n;i++)
        uf[i]=i,
        lz[i]=0,
        sz[i]=1;
    dfs(rt,1);
    for(i=1;i<=t;i++)
        printf(ans[i]?"Yes\n":"No\n");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/l-ly-03/p/DivideAndConquer-SegmentTreeDC.html