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)
输入数据以n=q=0结束。

输出

对于输入数据中的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 切蛋糕(并查集)的主要内容,如果未能解决你的问题,请参考以下文章

P3295 萌萌哒 并查集RMQ联动

❤️数据结构入门❤️(2 - 5)- 并查集

并查集

并查集并查集专题总结

数据结构----并查集

并查集-----好忧伤的并查集