您的位置:首页 > 其它

hdu5354 Bipartite Graph

2015-08-10 23:06 501 查看
  分治+并查集。假设要求[L,mid]的答案,那么很明显,如果一条边的两个端点都>mid的话或者一个端点>mid一个端点<L,说明询问[L,mid]这个区间中任何一点时候,这一条边都是连接的,否则的话递归下去处理。[mid+1,R]同理。

一个图不是二分图的话说明存在奇环,奇环可以用并查集处理。这里的并查集不使用路径压缩而使用按轶合并。并查集的还原操作可以用一个栈记录每次合并时的具体操作,然后按序还原即可。

  代码

#include<cstdio>
#include<vector>
#define N 300010
using namespace std;
int f
,d
;
int n,m,i,dp;
int tt
,pre
,p
,ans
,flag
;
int tot,stack
,a
,b
,g
;
vector<int> vec
;
void link(int x,int y)
{
dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;
}
int getfa(int x,int& y)
{
y=0;
while (x!=f[x])
{
y^=g[x];
x=f[x];
}
return x;
}
void Union(int x,int y,int &z)
{
int disx,disy;
x=getfa(x,disx);
y=getfa(y,disy);
if (x!=y)
{
if (d[x]>d[y]) x^=y^=x^=y;
f[x]=y;
g[x]=(disx^disy^1);
tot++;stack[tot]=x;
if (d[x]==d[y])
{
flag[tot]=1;
d[y]++;
}
else
flag[tot]=0;
}
else
{
if (disx^disy^1)
z|=1;
}
}
void recover(int x)
{
while (tot>x)
{
if (flag[tot])
d[f[stack[tot]]]--;
f[stack[tot]]=stack[tot];
g[stack[tot]]=0;
tot--;
}
}
void solve(int x,int l,int r,int q)
{
int i,tmp,len,t,Ans;
if (l==r)
{
ans[l]=1-q;
return;
}
int mid=(l+r)>>1;

vec[2*x].clear();
vec[2*x+1].clear();
tmp=tot;
Ans=q;
len=vec[x].size();
for (i=0;i<len;i++)
{
t=vec[x][i];
if ((a[t]>mid)||((a[t]<l)&&(b[t]>mid)))
Union(a[t],b[t],Ans);
else
vec[2*x].push_back(t);
}
solve(2*x,l,mid,Ans);

Ans=q;
recover(tmp);
for (i=0;i<len;i++)
{
t=vec[x][i];
if ((b[t]<mid+1)||((a[t]<mid+1)&&(b[t]>r)))
Union(a[t],b[t],Ans);
else
vec[2*x+1].push_back(t);
}
solve(2*x+1,mid+1,r,Ans);
}
int main()
{
int tt;
scanf("%d",&tt);
while (tt)
{
tt--;
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
{
g[i]=0;
f[i]=i;
}
tot=0;
vec[1].clear();
for (i=1;i<=m;i++)
{
scanf("%d%d",&a[i],&b[i]);
if (a[i]>b[i])
a[i]^=b[i]^=a[i]^=b[i];
vec[1].push_back(i);
}
solve(1,1,n,0);
for (i=1;i<=n;i++)
printf("%d",ans[i]);
printf("\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: