Reachability Query(Union-Find)

Time Limit: 3 sec / Memory Limit: 1024 MiB

Score : 450 points

Problem Statement

You are given an undirected graph with N vertices and zero edges.

The vertices are numbered 1,2,...,N, and initially all vertices are white.

Process a total of Q queries of the following three types:

  • Type 1 : Add an undirected edge connecting vertices u and v.
  • Type 2 : If vertex v is white, change it to black; if it is black, change it to white.
  • Type 3 : Determine whether a black vertex can be reached from vertex v by traversing zero or more edges; report Yes if reachable, and No otherwise.

Constraints

  • All input values are integers.
  • 1≤N≤
  • 1≤Q≤
  • Type 1 queries satisfy the following constraints:
    • 1≤u<v≤N
    • For each query, no edge connecting u and v has been added before that query.
  • Type 2,3 queries satisfy the following constraints:
    • 1≤v≤N

Input

The input is given from Standard Input in the following format:

复制代码
N 𝑄
Query1​
Query2​
⋮
QueryQ​

where Queryi​ represents the i-th query.

Type 1 queries are given in the following format:

复制代码
1 u v

Type 2 queries are given in the following format:

复制代码
2 v

Type 3 queries are given in the following format:

复制代码
3 v

Output

For each type 3 query, output the answer as follows:

  • Yes if a black vertex can be reached from vertex v by traversing zero or more edges;
  • No if no black vertex can be reached from vertex v by traversing zero or more edges.

Sample Input 1

cpp 复制代码
5 12
3 2
2 2
3 2
1 2 5
1 3 4
3 4
3 5
1 4 5
1 1 3
3 1
2 2
3 1

Sample Output 1

复制代码
No
Yes
No
Yes
Yes
No

In this input, the graph initially has five vertices and zero edges.

This input contains 12 queries.

  • The 1st query is 3 2.
    • At this point, no black vertex can be reached from vertex 2 by traversing zero or more edges, so report No.
  • The 2nd query is 2 2.
    • Vertex 22 is white, so change it to black.
  • The 3rd query is 3 2.
    • At this point, black vertex 22 can be reached from vertex 2 by traversing zero or more edges. Therefore, report Yes.
  • The 4th query is 1 2 5.
    • Add an edge connecting vertices 2,5.
  • The 5th query is 1 3 4.
    • Add an edge connecting vertices 3,4.
  • The 6th query is 3 4.
    • At this point, no black vertex can be reached from vertex 4 by traversing zero or more edges, so report No.
  • The 7th query is 3 5.
    • At this point, black vertex 2 can be reached from vertex 5 by traversing zero or more edges. Therefore, report Yes.
  • The 8th query is 1 4 5.
    • Add an edge connecting vertices 4,5.
  • The 9th query is 1 1 3.
    • Add an edge connecting vertices 1,3.
  • The 10th query is 3 1.
    • At this point, black vertex 2 can be reached from vertex 1 by traversing zero or more edges. Therefore, report Yes.
  • The 11th query is 2 2.
    • Vertex 2 is black, so change it to white.
  • The 12th query is 3 1.
    • At this point, no black vertex can be reached from vertex 1 by traversing zero or more edges, so report No.

思路分析

  1. 初始化:使用并查集(Union-Find)数据结构来管理连通分量。每个顶点初始时独立为一个分量,颜色均为白色,黑色计数为零。

  2. 处理查询

    • 类型1(添加边):合并两个顶点所在的连通分量,合并时黑色计数相加。

    • 类型2(切换颜色):改变顶点颜色,并更新所在分量的黑色计数。白色变黑色时计数增加,黑色变白色时计数减少。

    • 类型3(检查可达性):检查顶点所在分量的黑色计数是否大于零,若是则输出"Yes",否则输出"No"。

  3. 效率优化:并查集通过路径压缩和按秩合并优化,确保每次操作的时间复杂度接近常数,适用于大规模输入。

代码

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+5;
vector<int>fa(N),rankk(N,0),color(N,0),cnt_black(N,0);
int n,q,op,u,v;
int find(int x){
    if(fa[x]!=x){
        fa[x]=find(fa[x]);
    }
    return fa[x];
}
void unionset(int x,int y){
    int rx=find(x),ry=find(y);
    if(rx==ry)return;
    if(rankk[rx]>rankk[ry]){
        fa[ry]=rx;
        cnt_black[rx]+=cnt_black[ry];
    }
    else{
        if(rankk[rx]==rankk[ry])rankk[ry]++;
        fa[rx]=ry;
        cnt_black[ry]+=cnt_black[rx];
    }
}
vector<int>black(N,0);
int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>q;
    for(int i=1;i<=n;i++){
        fa[i]=i;
    }
    while(q--){
        cin>>op;
        if(op==1){
            cin>>u>>v;
            unionset(u,v);
        }
        else if(op==2){
            cin>>v;
            int c=color[v];
            if(c==0){
                color[v]=1;
                int root=find(v);
                cnt_black[root]++;
            }
            else{
                color[v]=0;
                int root=find(v);
                cnt_black[root]--;
            }
        }
        else{
            cin>>v;
            int root=find(v);
            if(cnt_black[root]>0){
                cout<<"Yes\n";
            }
            else{
                cout<<"No\n";
            }
        }
    }
    return 0;
}
相关推荐
田里的水稻几秒前
C++_python_相互之间的包含调用方法
c++·chrome·python
sinat_286945195 分钟前
opencode
人工智能·算法·chatgpt
HABuo13 分钟前
【Linux进程(四)】进程切换&环境变量深入剖析
linux·运维·服务器·c语言·c++·ubuntu·centos
工口发动机22 分钟前
ABC440DEF简要题解
c++·算法
带土128 分钟前
4. C++ static关键字
开发语言·c++
橘颂TA29 分钟前
【Linux】死锁四条件的底层逻辑:从锁冲突到 STL 组件的线程安全实践(Ⅵ)
linux·运维·服务器·c++·死锁
C++ 老炮儿的技术栈35 分钟前
什么是通信规约
开发语言·数据结构·c++·windows·算法·安全·链表
零小陈上(shouhou6668889)1 小时前
K-近邻算法 - lazy learning的代表
算法·近邻算法
有一个好名字1 小时前
力扣-从字符串中移除星号
java·算法·leetcode
萧瑟其中~1 小时前
二分算法模版——基础二分查找,左边界查找与右边界查找(Leetcode的二分查找、在排序数组中查找元素的第一个位置和最后一个位置)
数据结构·算法·leetcode