您的位置:首页 > 其它

[CDQ分治 并查集 || LCT] BZOJ 4025 二分图

2016-05-02 13:36 447 查看
Po姐的姿势:/article/2348623.html

LCT的做法:

考虑随便维护一个图的生成树,不难发现,如果一条边加入后,形成奇环的话就不是二分图
否则的话,我们可以无视这条边,因为如果之后再新加入一条边和这条边形成了一个奇环
那么新加入的边一定和原来生成树上的边也能形成奇环
所以我们直接维护一棵生成树即可
然后裸的想法就来了:上lct,维护以离开时间为边权的最大生成树,每次加边弹出环上最早离开的边

分治 并查集:
定义Solve(x,y,E)为当前处理的区间为[x,y],E为所有存在时间为[x,y]的子集的边的集合

那么对于E中的每一条边(u,v),讨论:

若当前边的存在时间为[x,y],则在并查集上判断是否出现奇环

如果出现,[x,y]内的所有时刻都一定不是二分图,输出答案即可

如果不出现,在并查集中连接(u,v)

否则判断存在时间和mid的关系讨论扔进左区间还是右区间还是都扔进去

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
using namespace std;

inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}

inline void read(int &x)
{
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=200005;

struct edge{
int x,y,l,r;
edge(int x,int y,int l,int r):x(x),y(y),l(l),r(r) { }
};

struct Operation{
int f,x;
Operation(int f=0,int x=0):f(f),x(x) { }
}Stk[4*N];
int top;

int fat
,rel
,rank
;

inline int Fat(int u){
while (fat[u]!=u) u=fat[u];
return u;
}

inline int Rel(int u){
int ret=0;
while (fat[u]!=u) ret^=rel[u],u=fat[u];
return ret;
}

inline void Union(int x,int y,int z){
if (rank[x]>rank[y]) swap(x,y);
if (rank[x]==rank[y]) rank[y]++,Stk[++top]=Operation(0,y);
fat[x]=y; rel[x]=z; Stk[++top]=Operation(1,x);
}

inline void Restore(int bottom){
while (top>bottom){
if (Stk[top].f==0)
rank[Stk[top].x]--;
else
fat[Stk[top].x]=Stk[top].x,rel[Stk[top].x]=0;
top--;
}
}

typedef vector<edge>::iterator ITER;

void Divi(int l,int r,vector<edge> E){
int mid=(l+r)>>1,bottom=top;
vector<edge> L,R;
for (ITER it=E.begin();it!=E.end();it++)
{
if (it->l==l && it->r==r)
{
int fx=Fat(it->x),fy=Fat(it->y),z=Rel(it->x)^Rel(it->y)^1;
if(fx!=fy)
Union(fx,fy,z);
else
{
if(z&1)
{
for(int i=l;i<=r;i++) printf("No\n");
Restore(bottom);
return ;
}
}
}
else if(it->r<=mid)
L.push_back(*it);
else if(it->l>mid)
R.push_back(*it);
else
L.push_back(edge(it->x,it->y,it->l,mid)),R.push_back(edge(it->x,it->y,mid+1,it->r));
}
if (l==r)
printf("Yes\n");
else
Divi(l,mid,L),Divi(mid+1,r,R);
Restore(bottom);
}

int n,m,T;

int main()
{
int x,y,l,r;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
vector<edge> e;
read(n); read(m); read(T);
for (int i=1;i<=n;i++)
fat[i]=i;
for (int i=1;i<=m;i++)
{
read(x); read(y); read(l); read(r);
l++; if (l>r) continue;
e.push_back(edge(x,y,l,r));
}
Divi(1,T,e);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: