TZOJ 3042 切蛋糕(并查集)
Posted taozi1115402474
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TZOJ 3042 切蛋糕(并查集)相关的知识,希望对你有一定的参考价值。
描述
KK是个心灵手巧的好姑娘,她做了一个大蛋糕请她的好朋友们来品尝。
这个蛋糕分成n×n个正方形小格,每个小格包含一块水果。KK要把蛋糕切成若干块,显然她不会破坏任意一个小格。
无聊的某同学在她切蛋糕时不停地问她同一种问题:某两个小格是否还在同一块蛋糕里?
例如下图中,KK从(1,1)切到(4,1),又从(1,1)切到(1,4),从而将蛋糕分成了两块。然后又从(2,1)切到(2,3),从(1,3)切到(2,3),于是把整个蛋糕分成了三块。其中小格(2,2)只和小格(2,3)连通,与其它所有小格不连通。
KK被这些无聊的问题烦透了,她请求你编写一个程序让他闭嘴。
输入
输入包括多组数据。
每组数据第一行为两个整数:蛋糕大小n (1≤n≤1000),以及KK切蛋糕次数和问题数之和q (1≤q≤100000)
然后q行,每行是下面两者之一,描述了切蛋糕和问问题的过程:
- cut x1 y1 x2 y2
沿着坐标(x1,y1)和(x2,y2)连成的直线段切割蛋糕。
输入数据确保x1=x2和y1=y2恰有其一成立,坐标(x1,y1)和(x2,y2)连成的直线段一定在蛋糕内部,并且KK不会重复切同一位置。 - query x1 y1 x2 y2
询问格子(x1,y1)和(x2,y2)是否在同一块蛋糕上(1≤x1, y1, x2, y2≤n)
输出
对于输入数据中的query问题,如果两个格子在同一块蛋糕上则输出”Yes”,否则输出”No”。
样例输入
4 11
query 1 1 2 2
cut 1 1 4 1
cut 1 1 1 4
query 1 1 2 2
query 2 2 3 3
cut 2 3 2 1
query 2 2 3 3
cut 1 3 2 3
query 2 2 3 3
query 2 2 2 3
query 1 1 2 4
1000 1
query 1 1 1000 1000
0 0
样例输出
Yes
No
Yes
Yes
No
Yes
No
Yes
题意
每次切一条线段,查询两块蛋糕是否被切开。
题解
相当于相邻蛋糕用边相连,然后删除一些边,询问是否连通。
只有删边操作,那么可以考虑并查集,因为并查集是加边操作,所以可以把问题倒过来。
每次加入并查集一条最后删掉的边。
并查集路径压缩和按秩合并均摊O(1)。
总时间复杂度O(n^2+q)。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int N=1e6+5; 5 const int M=1e5+5; 6 int f[N],d[N]; 7 bool g[1005][1005][2],ans[M]; 8 int dx[]=1,0; 9 int dy[]=0,1; 10 int n; 11 struct node 12 13 bool f;int x1,y1,x2,y2; 14 q[M]; 15 void init(int n) 16 17 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)for(int k=0;k<2;k++)g[i][j][k]=1; 18 int n1=n*n;for(int i=1;i<=n1;i++)d[i]=0,f[i]=i; 19 20 int F(int x)return f[x]==x?x:F(f[x]); 21 void merge(int x1,int y1,int x2,int y2) 22 23 int x=(x1-1)*n+y1,y=(x2-1)*n+y2; 24 x=F(x),y=F(y); 25 if(x==y)return; 26 if(d[x]==d[y])d[x]++; 27 if(d[x]<d[y])swap(x,y); 28 f[y]=x; 29 30 int main() 31 32 int Q;char s[7]; 33 while(scanf("%d%d",&n,&Q)!=EOF,n||Q) 34 35 init(n); 36 for(int i=1;i<=Q;i++) 37 38 scanf("%s%d%d%d%d",s,&q[i].y1,&q[i].x1,&q[i].y2,&q[i].x2); 39 if(s[0]==‘q‘)q[i].f=1; 40 else 41 42 q[i].f=0; 43 if(q[i].x1==q[i].x2) 44 45 if(q[i].x1==n)continue; 46 if(q[i].y1>q[i].y2)swap(q[i].y1,q[i].y2); 47 for(int j=q[i].y1+1;j<=q[i].y2;j++)g[q[i].x1][j][0]=0; 48 49 else 50 51 if(q[i].y1==n)continue; 52 if(q[i].x1>q[i].x2)swap(q[i].x1,q[i].x2); 53 for(int j=q[i].x1+1;j<=q[i].x2;j++)g[j][q[i].y1][1]=0; 54 55 56 57 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) 58 59 for(int k=0;k<2;k++) 60 if(g[i][j][k]&&i+dx[k]<=n&&j+dy[k]<=n) 61 merge(i,j,i+dx[k],j+dy[k]); 62 63 for(int i=Q;i>=1;i--) 64 65 if(q[i].f)//query 66 67 if(F((q[i].x1-1)*n+q[i].y1)==F((q[i].x2-1)*n+q[i].y2))ans[i]=1; 68 else ans[i]=0; 69 70 else//cut 71 72 if(q[i].x1==q[i].x2) 73 74 if(q[i].x1==n)continue; 75 for(int j=q[i].y1+1;j<=q[i].y2;j++) 76 merge(q[i].x1,j,q[i].x1+1,j); 77 78 else 79 80 if(q[i].y1==n)continue; 81 for(int j=q[i].x1+1;j<=q[i].x2;j++) 82 merge(j,q[i].y1,j,q[i].y1+1); 83 84 85 86 for(int i=1;i<=Q;i++)if(q[i].f)printf("%s\\n",ans[i]?"Yes":"No"); 87 88 return 0; 89
以上是关于TZOJ 3042 切蛋糕(并查集)的主要内容,如果未能解决你的问题,请参考以下文章