题意

   给定一张 \(n\) 个点 \(m\) 条边的无向图,问删去每个点后,原图是不是二分图。输出一个长度为 \(n\) 的 \(\text{01}\) 串表示答案。

   多组数据。

   \(T\le 5,\space 1\le n,m\le 10^5,\space 1\le u,v\le n,\space u≠v\)

题解

   不难发现,一个没有奇环(奇数条边的环)的图就是二分图。

   考虑分治,若一个分治区间外的点已经连出了奇环,那删掉这个区间的每个点的答案都是 \(0\)。若分治到区间长度为 \(1\) 时,这个区间外的点还没连出奇环,那删掉这个点的答案就是 \(1\)。

   可以用并查集检测奇环,但由于分治回溯时需要撤销连边,不能路径压缩,所以用按秩合并的并查集。注意按照大小合并,按深度合并会 TLE。

   考虑如何判断新加的一条边的两端点是否颜色相同(即是否连出奇环)。

   初始时设每个点的颜色为 \(0\)(也可以为 \(1\),这里为了让接下来的操作方便理解,就设成 \(0\))。不难发现当两个并查集合并时,连接这两个并查集的边的两端点的颜色可能相同,这时我们最简单的解决方式是 把小的并查集的所有点的颜色都反转。

   但是我们显然不能暴力扫一遍子树,这样复杂度是错的。

   回想一下,我们按秩合并的并查集的深度是不是 \(\log\) 的?

   那我们求一个点的颜色时,只需要从这个点往根扫一遍就行了吧?

   所以我们只需要修改小的并查集的根节点颜色。具体地,并查集的每个点维护一个 \(\text{01}\) 标记,\(\text{0}\) 表示以该点为根的子树不翻转颜色,\(\text{1}\) 表示以该点为根的子树翻转颜色。一个点的颜色就是 该点 到 其所在的并查集的根节点 上所有点颜色的异或和。

   一个细节:边一定都是从小分治区间的点 往大分治区间的点连。

#include<bits/stdc++.h>
#define N 100010
using namespace std;
inline int read(){
int x=0; bool f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
if(f) return x;
return 0-x;
} int n,m,col[N],fa[N],siz[N];
char ans[N]; struct edge{int v,nxt;}e[N<<1];
int hd[N],cnt;
inline void add(int u, int v){e[++cnt]=(edge){v,hd[u]}, hd[u]=cnt;} struct DSU{int u,v,col_u,col_v,siz_u,siz_v;}stk[N],tmp;
int top; inline void init(){
top=cnt=0;
ans[n+1]=0;
for(int i=1; i<=n; ++i) hd[i]=col[i]=0, siz[i]=1, fa[i]=i;
}
int find_fa(int x){
return fa[x]==x ? x : find_fa(fa[x]);
}
int find_col(int x){
if(fa[x]==x) return col[x]; //显然根的col为0
return find_col(fa[x])^col[x];
}
int merge(int u, int v){
int fa_u=find_fa(u), fa_v=find_fa(v);
int col_u=find_col(u), col_v=find_col(v);
//cout<<u<<' '<<v<<' '<<fa_u<<' '<<fa_v<<' '<<col_u<<' '<<col_v<<endl;
if(fa_u==fa_v){
if(col_u==col_v) return 0;
return 1;
}
int rt,son;
if(siz[fa_u]<siz[fa_v]) rt=fa_v, son=fa_u;
else rt=fa_u, son=fa_v;
//cout<<rt<<endl;
stk[++top] = (DSU){rt,son,col[rt],col[son],siz[rt],siz[son]};
if(col_u==col_v) col[son]^=1;
fa[son]=rt, siz[rt]+=siz[son];
return 1;
}
void undo(int pre){
//printf("undo\n");
while(top>pre){
tmp=stk[top--];
int u=tmp.u, v=tmp.v;
col[u]=tmp.col_u, col[v]=tmp.col_v;
fa[u]=u, fa[v]=v;
siz[u]=tmp.siz_u, siz[v]=tmp.siz_v;
}
}
int unite(int l, int r, int a, int b){
//printf("unite\n");
for(int j=l; j<=r; ++j)
for(int i=hd[j]; i; i=e[i].nxt){
if(a<=e[i].v && e[i].v<=b) continue;
if(!merge(j,e[i].v)) return 0;
}
return 1;
}
void cdq(int l, int r, bool flag){
//printf("cdq:%d %d %d\n",l,r,flag);
if(l==r){ans[l]=flag+'0'; return;}
int mid=l+r>>1;
if(!flag){
cdq(l,mid,0), cdq(mid+1,r,0);
return;
}
int pre=top; bool now=unite(mid+1,r,l,mid);
cdq(l,mid,now), undo(pre);
now = unite(l,mid,mid+1,r);
cdq(mid+1,r,now), undo(pre);
}
int main(){
int T=read();
while(T--){
n=read(), m=read();
init();
int u,v;
for(int i=1; i<=m; ++i) u=read(), v=read(), add(u,v), add(v,u);
cdq(1,n,1);
printf("%s\n",ans+1);
}
return 0;
}

【bzoj 4025 改编版】graph的更多相关文章

  1. bzoj 4025 二分图 分治+并查集/LCT

    bzoj 4025 二分图 [题目大意] 有n个点m条边,边会在start时刻出现在end时刻消失,求对于每一段时间,该图是不是一个二分图. 判断二分图的一个简单的方法:是否存在奇环 若存在奇环,就不 ...

  2. [BZOJ 4025]二分图(线段树分治+带边权并查集)

    [BZOJ 4025]二分图(线段树分治+带边权并查集) 题面 给出一个n个点m条边的图,每条边会在时间s到t出现,问每个时间的图是否为一个二分图 \(n,m,\max(t_i) \leq 10^5\ ...

  3. BZOJ 4025: 二分图 [线段树CDQ分治 并查集]

    4025: 二分图 题意:加入边,删除边,查询当前图是否为二分图 本来想练lct,然后发现了线段树分治的做法,感觉好厉害. lct做法的核心就是维护删除时间的最大生成树 首先口胡一个分块做法,和hno ...

  4. BZOJ百题版切计划(不咕)

    传送门 BZOJ 前言 听说最近要省选,那么我就写一下吧.QwQ! 1000 过于简单,不写了. 1001 不会对偶图,直接优化最小割 题解 1002 高精度套公式计算 题解 (Code by hey ...

  5. bzoj 4025 二分图——线段树分治+LCT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4025 线段树分治,用 LCT 维护链的长度即可.不过很慢. 正常(更快)的方法应该是线段树分 ...

  6. 【BZOJ 4025】 (CDQ?还是整体二分?+并查集及它的恢复操作)

    4025: 二分图 Description 神犇有一个n个节点的图.因为神犇是神犇,所以在T时间内一些边会出现后消失.神犇要求出每一时间段内这个图是否是二分图.这么简单的问题神犇当然会做了,于是他想考 ...

  7. BZOJ 4025 二分图(时间树+并查集)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4025 [题目大意] 给出一张图,有些边只存在一段时间,问在一个每个时间段, 这张图是否 ...

  8. bzoj 4025: 二分图

    Description 神犇有一个n个节点的图.因为神犇是神犇,所以在T时间内一些边会出现后消失.神犇要求出每一时间段内这个图是否是二分图.这么简单的问题神犇当然会做了,于是他想考考你. 解题报告: ...

  9. https://github.com/tensorflow/models/blob/master/research/slim/datasets/preprocess_imagenet_validation_data.py 改编版

    #!/usr/bin/env python # Copyright 2016 Google Inc. All Rights Reserved. # # Licensed under the Apach ...

随机推荐

  1. Eclipse MAT和jvisualvm分析内存溢出

    ---------------------------------------------mac os版------------------------------------------------ ...

  2. 自动添加 ssh key 到远程主机的脚本,应用sshpass和ssh-copy-id

    USERNAME=$ PASSWORD=$ HOST=$ if [ "$3" = "" ]; then echo "Missing parameter ...

  3. JavaScript基础入门04

    目录 JavaScript 基础入门04 JavaScript 对象 介绍 关于键名 对象的引用 语句和表达式需要注意的地方 对象属性常见的操作 with语句 JSON 特点 语法规则 JSON合法示 ...

  4. WEB框架初识

    HTTP介绍 Hyper Text Transfer Protocol,超文本传输书协议,是万维网数据通信的基础,规定了请求和响应标准. HTTP工作原理 HTTP 请求以及响应的步骤 客户端连接到W ...

  5. 给Date的构造函数添加属性和方法

    let d = Date.prototype; Object.defineProperties(d, { 'year': { get: function () { return this.getFul ...

  6. MySQL数据类型 约束

    一.数据库CDGS. 库 增   create database 库名; 删   drop 库名; 改 alter database 库名称 修改的属性名称; 查 show databases;#查看 ...

  7. 吉首大学2019年程序设计竞赛(重现赛)-J(树形DP)

    题目链接:https://ac.nowcoder.com/acm/contest/992/J 题意:题意很清晰,就是求任意两点距离的和,结果对1e9+7取模. 思路:裸的树形DP题,一条边的贡献值=这 ...

  8. java 利用辗除法求两个整数的最大公约数和最小公倍数

    题目:输入两个正整数m和n,求其最大公约数和最小公倍数. 程序分析:利用辗除法. package Studytest; import java.util.Scanner; public class P ...

  9. [转帖]爬过这 6 个坡,你就能对 Linux 操作系统了如指掌

    爬过这 6 个坡,你就能对 Linux 操作系统了如指掌 http://www.51testing.com/html/16/n-4461316.html 学习的任务 任重道远 我现在处于第一阶段. 发 ...

  10. [转帖]ASML发布Q1季度财报 营收22.3亿欧元,EUV光刻机下半年产能大增 ...

    ASML发布Q1季度财报营收22.3亿欧元,EUV光刻机下半年产能大增 ... 孟宪瑞发布于2019-4-18 10:32 https://www.expreview.com/67969.html 一 ...