(并查集)Codeforces 325 D-Reclamation

借用 链接 的题意和解法分析的图片。

对于这种环的形式,先用常用的手段复制一份在右边。每次加点的过程只要看加完之后能不能通过已有的格子联通,如果联通则显然已经形成了一个环。这里判断联通我采用的办法是,分别看两个点八个方向是否联通的无脑办法。想法很明确,但实现的过程中要注意一些细节,如列坐标<=0或>2*m的处理。

  1 #include <iostream>
  2 #include <string>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <queue>
  8 #include <set>
  9 #include <map>
 10 #include <list>
 11 #include <vector>
 12 #include <stack>
 13 #define mp make_pair
 14 //#define P make_pair
 15 #define MIN(a,b) (a>b?b:a)
 16 //#define MAX(a,b) (a>b?a:b)
 17 typedef long long ll;
 18 typedef unsigned long long ull;
 19 const int MAX=18e6+5;
 20 const int MAX_V=1e3+5;
 21 const int INF=1e9+5;
 22 const ll INF2=4e18+5;
 23 const double M=4e18;
 24 using namespace std;
 25 const int MOD=1e9+7;
 26 typedef pair<ll,int> pii;
 27 const double eps=0.000000001;
 28 #define rank rankk
 29 int an;
 30 int par[MAX];//父亲
 31 int rank[MAX];//树的高度
 32 //初始化n个元素
 33 void init(int n)
 34 {
 35     for(int i=0;i<n;i++)
 36     {
 37         par[i]=i;
 38         rank[i]=0;
 39     }
 40 }
 41 //查询树的根,期间加入了路径压缩
 42 int find(int x)
 43 {
 44     if(par[x]==x)
 45         return x;
 46     else
 47         return par[x]=find(par[x]);
 48 }
 49 //合并x和y所属的集合
 50 void unite(int x,int y)
 51 {
 52     x=find(x);
 53     y=find(y);
 54     if(x==y)
 55         return ;
 56     if(rank[x]<rank[y])
 57         par[x]=y;
 58     else
 59     {
 60         par[y]=x;
 61         if(rank[x]==rank[y])
 62             rank[x]++;
 63     }
 64 }
 65 //判断x和y是否属于同一个集合
 66 bool same(int x,int y)
 67 {
 68     return find(x)==find(y);
 69 }
 70 int n,m,q;
 71 int a[MAX];
 72 int dx[8]={-1,-1,-1,0,0,1,1,1};
 73 int dy[8]={-1,0,1,-1,1,-1,0,1};
 74 bool vi[3005][6005];
 75 int idx(int x,int y)//x行y列
 76 {
 77     return (x-1)*2*m+y;
 78 }
 79 bool check(int x,int &y)
 80 {
 81     return x>=1&&x<=n&&y>=1&&y<=2*m;
 82 }
 83 int solve(int x,int y)
 84 {
 85     int x2=x,y2=y+m;
 86     for(int i=0;i<8;i++)
 87     {
 88         int x1=x+dx[i],y1=y+dy[i];
 89         if(y1<1)
 90             y1+=2*m;
 91         else if(y1>2*m)
 92             y1-=2*m;
 93         if(check(x1,y1)&&vi[x1][y1])
 94         {
 95             for(int j=0;j<8;j++)
 96             {
 97                 int x3=x2+dx[j],y3=y2+dy[j];
 98                 if(check(x3,y3)&&vi[x3][y3])
 99                     if(same(idx(x3,y3),idx(x1,y1)))
100                        return 0;
101             }
102         }
103     }
104     return 1;
105 }
106 int main()
107 {
108     scanf("%d%d%d",&n,&m,&q);
109     if(m==1)
110         return 0*printf("0\n");
111     init(2*n*m+3);
112     int Max=2*m;
113     while(q--)
114     {
115         int x,y;
116         scanf("%d%d",&x,&y);
117             if(solve(x,y))
118             {
119                 vi[x][y]=vi[x][y+m]=true;
120                 ++an;
121                 for(int i=0;i<8;i++)
122                 {
123                     int x1=x+dx[i],y1=y+dy[i];
124                     if(y1<=0)
125                         y1+=Max;
126                     else if(y1>Max)
127                         y1-=Max;
128                     if(check(x1,y1)&&vi[x1][y1])
129                         unite(idx(x,y),idx(x1,y1));
130                     y1+=m;
131                     if(y1<=0)
132                         y1+=Max;
133                     else if(y1>Max)
134                         y1-=Max;
135                     if(check(x1,y1)&&vi[x1][y1])
136                         unite(idx(x,y+m),idx(x1,y1));
137                 }
138             }
139     }
140     printf("%d\n",an);
141     return 0 ;
142 }
时间: 2024-10-01 06:03:16

(并查集)Codeforces 325 D-Reclamation的相关文章

DFS/并查集 Codeforces Round #286 (Div. 2) B - Mr. Kitayuta&#39;s Colorful Graph

题目传送门 1 /* 2 题意:两点之间有不同颜色的线连通,问两点间单一颜色连通的路径有几条 3 DFS:暴力每个颜色,以u走到v为结束标志,累加条数 4 注意:无向图 5 */ 6 #include <cstdio> 7 #include <iostream> 8 #include <algorithm> 9 #include <cstring> 10 #include <string> 11 #include <vector> 1

(线段树+并查集) Codeforces Round #416 (Div. 2) E Vladik and Entertaining Flags

In his spare time Vladik estimates beauty of the flags. Every flag could be represented as the matrix n?×?m which consists of positive integers. Let's define the beauty of the flag as number of components in its matrix. We call component a set of cel

Codeforces Round #396 (Div. 2) D题Mahmoud and a Dictionary(并查集)解题报告

Mahmoud wants to write a new dictionary that contains n words and relations between them. There are two types of relations: synonymy (i. e. the two words mean the same) and antonymy (i. e. the two words mean the opposite). From time to time he discov

Codeforces 755C:PolandBall and Forest(并查集)

http://codeforces.com/problemset/problem/755/C 题意:该图是类似于树,给出n个点,接下来p[i]表示在树上离 i 距离最远的 id 是p[i],如果距离相等则p[i]是 id 较小的点. 思路:一开始没什么想法,画几分钟图发现不到什么东西,后来想着 i 和 p[i] 有关系,那么就代表 i 和 p[i] 是属于同一棵树,那么不就是并查集了嘛.抱着试一试的心态搞了一下居然过了. 1 #include <cstdio> 2 #include <c

Educational Codeforces Round 14 D. Swaps in Permutation (并查集orDFS)

题目链接:http://codeforces.com/problemset/problem/691/D 给你n个数,各不相同,范围是1到n.然后是m行数a和b,表示下标为a的数和下标为b的数可以交换无数次.问你最后字典序最大的数列是什么. 将下面的a和b用并查集联系起来存到祖节点对应的数组中,然后从大到小排序数组,最后依次按照父节点的数组中的顺序输出. 也可以用dfs的方法解(略麻烦),形成一个环路的就在一个数组中... 1 //并查集 2 #include <bits/stdc++.h> 3

CodeForces 510B 无向图找环的两种方法(搜索与并查集)

题目连接:http://codeforces.com/problemset/problem/510/B 解法: dfs 每次把父节点的值记录并传递下去,判断一下新达到节点: (1)没有走过 → 继续搜索: (2)走过&&不是父节点(对于本题步数也要>=4) → 找到环: 并查集 每个节点映射成 i*m+j从起点开始分别把它下面与于右面的节点加进来,如果发现有节点已经在集合中,那么环已经找到了. DFS: #include<cstdio> #include<cstdl

Codeforces Round #254 (Div. 2) B. DZY Loves Chemistry (并查集)

题目链接 昨天晚上没有做出来,刚看题目的时候还把题意理解错了,当时想着以什么样的顺序倒,想着就饶进去了, 也被题目下面的示例分析给误导了. 题意: 有1-n种化学药剂  总共有m对试剂能反应,按不同的次序将1-n种试剂滴入试管,如果正在滴入的试剂能与已经滴入 的试剂反应,那么危险数*2,否则维持不变.问最后最大的危险系数是多少. 分析:其实这个题根本不用考虑倒入的顺序,只是分块就行,结果就是每个子集里元素的个数-1 和  的2的幂. 1 #include <iostream> 2 #inclu

Codeforces Round #423 (Div. 2) C 思维,并查集 或 线段树 D 树构造,水

Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) C. String Reconstruction   思维,并查集 或 线段树 题意:一个字符串被删除了,但给出 n条信息,要还原出可能的字典序最小的字符串.信息有:字符串ti,ki个位置xi,表明原本的字符串在xi位置是以字符串ti开头的. tags:惨遭 fst,一开始把所有字符串都存下来,排序做的,结果爆内存了.. 方法1: 考虑并查集,对于字符串 ti,在位置xi,

Codeforces 731C:Socks(并查集)

http://codeforces.com/problemset/problem/731/C 题意:有n只袜子,m天,k个颜色,每个袜子有一个颜色,再给出m天,每天有两只袜子,每只袜子可能不同颜色,问要让每天的袜子是相同颜色的,要重新染色的袜子数最少是多少. 思路:并查集合并,将同一天的袜子合并起来,然后就形成了cnt个集合,每个集合都是独立的,因此排序,找出每个集合里面袜子颜色相同的最多的是哪个颜色,然后把其他不属于这个颜色的都染成这个颜色,那么这样重新染色的袜子数是最少的.然后每个集合的答案

【搜索】【并查集】Codeforces 691D Swaps in Permutation

题目链接: http://codeforces.com/problemset/problem/691/D 题目大意: 给一个1到N的排列,M个操作(1<=N,M<=106),每个操作可以交换X Y位置上的数字,求可以得到的最大字典序的数列. 题目思路: [搜索][并查集] 这题可以用搜索或者并查集写,都能过. 把位置分成若干块,每一块里面的位置都是可以被这一块里另一个位置经过若干次调换的(类似强连通,位置可达). 然后把每一块位置里的 位置按从小到大排序,位置上的值按从大到小排序,依次填入位置