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 }

原文地址:https://www.cnblogs.com/taozi1115402474/p/11626133.html

时间: 2024-10-13 19:21:37

TZOJ 3042 切蛋糕(并查集)的相关文章

hdu 5458 Stability(树链剖分+并查集)

Stability Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)Total Submission(s): 1347    Accepted Submission(s): 319 Problem Description Given an undirected connected graph G with n nodes and m edges, with possibly r

P3295 萌萌哒 并查集RMQ联动

又切一道紫题!!! 成功的(看了一吨题解之后),我A掉了第二道紫题. 好,我们仔细观察,发现这是一个排列组合问题. 有些限定条件,要相等的地方,我们就用并查集并起来.最后一查有多少个并查集,就有多少个位置可供自由选择. 所以答案就是10^(并查集数),去除前导0:*(9/10) 好,这样我们得到了一个O(mn)算法. 然后我们考虑优化:每个区间可能被合并多次.所以我们有两种选择:线段树/ST表. 考虑到这是ST表例题(???????),我们就来个ST表与并查集联动求解... 我们的ufs[i][

银河英雄传说(带权并查集)

题意就是要维护并查集,切询问两个点是不是在一棵树上,如果是,输出他们间的数减一 #include<iostream> #include<cstdio> using namespace std; int re(){ char c=getchar();int all=0,pd=1; for(;c>'9'||c<'0';c=getchar()) if(c=='-') pd=-1; while(c>='0'&&c<='9') all=all*10+c

CodeForces 745C Hongcow Builds A Nation 并查集

题意: 给了你n个城市 m条边 k个政府 每个政府管辖的区域内不能和其他政府的区域有相连 即政府之间不存在路径 问你在维护这种关系的同时 最多再加多少条边 思路: 先找出来每个联通块 再找出来没有归属的孤立的点 把他们都放到最大的联通块里 然后每个联通块之间的点两两连边是n*(n-1)/2条边 最后算出来的ans-m就好了 (看别人的博客学了一个max_element 1 #include<bits/stdc++.h> 2 #define cl(a,b) memset(a,b,sizeof(a

并查集(个人模版)

并查集: 1 int find(int a) 2 { 3 int r=a; 4 while(f[r]!=r) 5 r=f[r]; 6 int i=a; 7 int j; 8 while(i!=r) 9 { 10 j=f[i]; 11 f[i]=r; 12 i=j; 13 } 14 return r; 15 } 16 int merge(int a,int b) 17 { 18 int A,B; 19 A=find(a); 20 B=find(b); 21 if(A!=B) 22 { 23 f[B

并查集应用

题目描述: One way that the police finds the head of a gang is to check people's phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls

【bzoj3674】 可持久化并查集加强版

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 (题目链接) 题意 维护并查集3个操作:合并:回到完成第k个操作后的状态:查询. Solution 其实就是用主席树的叶子节点维护并查集的可持久化数组fa[]. 细节 终于认识到了按秩合并的强大,单纯写个路径压缩Re飞,写了路径压缩+按秩合并比单纯的按秩合并每快多少→_→ 代码 // bzoj3674 #include<algorithm> #include<iostream>

BZOJ1015[JSOI2008]星球大战starwar[并查集]

1015: [JSOI2008]星球大战starwar Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 5253  Solved: 2395[Submit][Status][Discuss] Description 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧道互相直接或间接地连接. 但好景不长,很快帝国又重

HDU 5606 tree 并查集

tree 把每条边权是1的边断开,发现每个点离他最近的点个数就是他所在的连通块大小. 开一个并查集,每次读到边权是0的边就合并.最后Ans?i??=size[findset(i)],size表示每个并查集根的size Ans_i=size[findset(i)],sizeAns?i??=size[findset(i)],size表示每个并查集根的sizesize. #include<cstdio> #include<cstring> #include<algorithm>