题目描述
这是一道被离线爆艹的模板题。
你要维护一张无向简单图。你被要求加入删除一条边及查询两个点是否连通。
- 0:加入一条边。保证它不存在。
- 1:删除一条边。保证它存在。
- 2:查询两个点是否联通。
输入格式
输入的第一行是两个数 N MN\ MN M。N≤5000,M≤500000N \leq 5000,M \leq 500000N≤5000,M≤500000。
接下来 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 200N≤200,M≤200
对于数据点 2,N=5,M≤30N=5,M \leq 30N=5,M≤30
对于数据点 3,N=10,M≤1000N=10,M \leq 1000N=10,M≤1000,其中查询的次数 ≥900\geq 900≥900 次。
对于数据点 4,N=300,M≤50000N=300,M \leq 50000N=300,M≤50000
对于数据点 5,N=5000,M≤200000N=5000,M \leq 200000N=5000,M≤200000,没有操作 1,其中约 70%70 \%70% 是操作 2。
对于数据点 6,N=5000,M≤200000N=5000,M \leq 200000N=5000,M≤200000,没有操作 1,其中约 70%70 \%70% 是操作 0。
对于数据点 7、8,N=100,M≤500000N=100,M \leq 500000N=100,M≤500000
对于数据点 9,N=5000,M≤500000N=5000,M \leq 500000N=5000,M≤500000,图是一棵树,其直径 ≤6 \leq 6≤6 。
对于数据点 10, N=5000,M≤500000N=5000,M \leq 500000N=5000,M≤500000,图是一棵树,其每个点度数 ≤4 \leq 4≤4 。
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; }