把操作拆成若干作用在不同时间段的操作,时间段划分按线段树划分方式,因此才叫线段树分治。
以下就以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; }