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