loj #121. 「离线可过」动态图连通性

人盡茶涼 提交于 2021-02-14 16:02:26

#121. 「离线可过」动态图连通性

内存限制:512 MiB时间限制:800 ms标准输入输出
题目类型:传统评测方式:文本比较
上传者: EtaoinWu

题目描述

这是一道被离线爆艹的模板题。

你要维护一张无向简单图。你被要求加入删除一条边及查询两个点是否连通。

  • 0:加入一条边。保证它不存在。
  • 1:删除一条边。保证它存在。
  • 2:查询两个点是否联通。

输入格式

输入的第一行是两个数 N MN\ MN M。N≤5000,M≤500000N \leq 5000,M \leq 500000N5000,M500000。

接下来 MMM 行,每一行三个数 op x y\text{op} \ x \ yop x y。op\text{op}op 表示操作编号。

输出格式

对于每一个 op=2\text{op}=2op=2 的询问,输出一行 Y 或 N ,表示两个节点是否连通。

样例

样例输入 1

200 5
2 123 127
0 123 127
2 123 127
1 127 123
2 123 127

样例输出 1

N
Y
N

样例输入 2

4 10
0 1 2
0 2 3
0 3 1
2 1 4
0 4 3
2 1 4
1 2 3
2 1 4
1 1 3
2 1 4

样例输出 2

N
Y
Y
N

数据范围与提示

对于数据点 1,N≤200,M≤200N \leq 200,M \leq 200N200,M200

对于数据点 2,N=5,M≤30N=5,M \leq 30N=5,M30

对于数据点 3,N=10,M≤1000N=10,M \leq 1000N=10,M1000,其中查询的次数 ≥900\geq 900900 次。

对于数据点 4,N=300,M≤50000N=300,M \leq 50000N=300,M50000

对于数据点 5,N=5000,M≤200000N=5000,M \leq 200000N=5000,M200000,没有操作 1,其中约 70%70 \%70% 是操作 2。

对于数据点 6,N=5000,M≤200000N=5000,M \leq 200000N=5000,M200000,没有操作 1,其中约 70%70 \%70% 是操作 0。

对于数据点 7、8,N=100,M≤500000N=100,M \leq 500000N=100,M500000

对于数据点 9,N=5000,M≤500000N=5000,M \leq 500000N=5000,M500000,图是一棵树,其直径 ≤6 \leq 66 。

对于数据点 10, N=5000,M≤500000N=5000,M \leq 500000N=5000,M500000,图是一棵树,其每个点度数 ≤4 \leq 44 。

P.S. 其实 9 是菊花,10 是单链,而没有放随机树的点...

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 5010
using namespace std;
int n,m,head[maxn],num,cntp[3],fa[maxn];
int map[5010][5010];
bool vis[maxn];
struct node{int to,pre,v;}e[1000010];
struct Node{int op,x,y;}p[500010];
void Insert(int from,int to){
    e[++num].to=to;
    e[num].v=1;
    e[num].pre=head[from];
    head[from]=num;
    map[from][to]=num;
}
bool bfs(int s,int t){
    queue<int>q;
    memset(vis,0,sizeof(vis));
    q.push(s);vis[s]=1;
    while(!q.empty()){
        int now=q.front();q.pop();
        for(int i=head[now];i;i=e[i].pre){
            if(!e[i].v)continue;
            int to=e[i].to;
            if(!vis[to]){
                vis[to]=1;q.push(to);
                if(to==t)return 1;
            }
        }
    }
    return vis[t]==1;
}
void work1(){
    for(int i=1;i<=m;i++){
        if(p[i].op==0){//加入 
            int pos1=map[p[i].x][p[i].y];
            int pos2=map[p[i].y][p[i].x];
            if(pos1){
                e[pos1].v=1;
                e[pos2].v=1;
            }
            else {
                Insert(p[i].x,p[i].y);
                Insert(p[i].y,p[i].x);
            }
        }
        else if(p[i].op==1){//删除 
            int pos1=map[p[i].x][p[i].y];
            int pos2=map[p[i].y][p[i].x];
            e[pos1].v=0;e[pos2].v=0;
        }
        else {//查询 
            if(bfs(p[i].x,p[i].y))puts("Y");
            else puts("N");
        }
    }
}
int find(int x){
    if(x==fa[x])return x;
    return fa[x]=find(fa[x]);
}
void work2(){
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        int f1=find(p[i].x),f2=find(p[i].y);
        if(p[i].op==0){
            if(f1!=f2)fa[f1]=f2;
        }
        else {
            if(f1==f2)puts("Y");
            else puts("N");
        }
    }
}
int main(){
    freopen("Cola.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&p[i].op,&p[i].x,&p[i].y);
        cntp[p[i].op]++;
    }
    if(cntp[1]==0){work2();return 0;}
    work1();
    return 0;
}
81分 暴力

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!