P5787 二分图 /【模板】线段树分治

题目描述

神犇有一个 nn 个节点的图。

因为神犇是神犇,所以在 kk 时间内有 mm 条边会出现后消失。

神犇要求出每一时间段内这个图是否是二分图。

这么简单的问题神犇当然会做了,于是他想考考你。

原 BZOJ4025。

输入格式

第一行三个整数 n,m,kn,m,k。

接下来 mm 行,每行四个整数 x,y,l,rx,y,l,r,表示有一条连接 x,yx,y 的边在 ll 时刻出现 rr 时刻消失。

输出格式

kk 行,第 ii 行一个字符串 Yes 或 No,表示在第 ii 时间段内这个图是否是二分图。

输入输出样例

输入 #1
3 3 3
1 2 0 2
2 3 0 3
1 3 1 2
输出 #1
Yes
No
Yes

说明/提示

样例说明

00 时刻,出现两条边 (1,2)(1,2) 和 (2,3)(2,3)。

第 11 时间段内,这个图是二分图,输出 Yes

11 时刻,出现一条边 (1,3)(1,3)。

第 22 时间段内,这个图不是二分图,输出 No

22 时刻,(1,2)(1,2) 和 (1,3)(1,3) 两条边消失。

第 33 时间段内,只有一条边 (2,3)(2,3),这个图是二分图,输出 Yes

数据范围

n,k = 10^5n,k=105,m = 2\times 10^5m=2×105。1 \le x,y \le n1x,yn,0 \le l \le r \le k0lrk。

注意

本题设有 hack 数据(Subtask 22),计 00 分,但若没有通过 hack 数据则不算通过本题。

题解

线段树分治康复,代码有注释

代码

 1 //每个操作都有一段存在的时间,将所有操作拆分并覆盖到线段树上。
 2 //DFS线段树,进入节点的时候加入所有这些节点的操作,出节点的时候撤销这些操作,DFS到叶子的时候统计一下答案。 
 3 #include<bits/stdc++.h>
 4 #define N (100009)
 5 using namespace std;
 6 int n,m,k,fa[N<<1],dep[N<<1],top;
 7 vector<pair<int,int> > e[N<<2];
 8 pair<int,int>st[N<<1];
 9 void Update(int now,int l,int r,int l1,int r1,int x,int y) {
10     if (l>r1 || r<l1) return;
11     if (l1<=l && r<=r1) {
12         e[now].push_back(make_pair(x,y));
13         return;
14     }
15     int mid=(l+r)>>1;
16     Update(now<<1,l,mid,l1,r1,x,y);
17     Update(now<<1|1,mid+1,r,l1,r1,x,y);
18 }
19 int Find(int x) {
20     return x==fa[x]?x:Find(fa[x]);
21 }
22 void Merge(int fx,int fy) {
23     if (dep[fx]>dep[fy]) swap(fx,fy);
24     fa[fx]=fy; dep[fy]+=(dep[fx]==dep[fy]);
25     st[++top]=make_pair(fx,fy);
26 }//按秩合并并查集,用栈存历史操作,方便撤销
27 void DFS(int now,int l,int r,int flag) {
28     int mid=(l+r)>>1, tmp=top;
29     for (int i=0; i<e[now].size(); ++i) {
30         int x=e[now][i].first, y=e[now][i].second;
31         int fx=Find(x), fy=Find(y), fx_=Find(x+n), fy_=Find(y+n);
32         if (fx==fy) {
33             flag=0;
34             break;
35         }
36         Merge(fx,fy_); Merge(fy,fx_);
37     }
38     if (l<r) DFS(now<<1,l,mid,flag), DFS(now<<1|1,mid+1,r,flag);
39     else puts(flag?"Yes":"No");
40     for (int i=top; i>tmp; --i) {
41         int fx=st[i].first, fy=st[i].second;
42         fa[fx]=fx; dep[fy]-=(dep[fx]+1==dep[fy]);
43     }
44     top=tmp;
45 }//并查集判断二分图,加入边(x,y)时若x和y在一个集合就不能构成二分图,否则能构成且合并(x,y'),(x',y)
46 int main() {
47     cin>>n>>m>>k;
48     for (int i=1; i<=2*n; ++i) fa[i]=i, dep[i]=1;
49     for (int i=1; i<=m; ++i) {
50         int x,y,l,r;
51         cin>>x>>y>>l>>r;
52         Update(1,0,k-1,l,r-1,x,y);
53     }
54     DFS(1,0,k-1,1);
55 }
posted @ 2021-07-27 16:12  Refun  阅读(89)  评论(0编辑  收藏  举报