[USACO18OPEN] Multiplayer Moo (并查集+维护并查集技巧)

题目大意:给你一个N*N的棋盘,棋盘上每个点都有一个权值

第一问求一个权值形成的最大联通块中点的数量

第一问求两个权值共同形成的最大联通块中点的数量

提供一种并查集的做法:(感谢大佬们的题解)
第一问把所有相同权值的相邻的点用带权并查集合并一下就OK了

第二问,就需要一些骚操作了

我们的目的是把两个不同权值的所有联通块合并,再去看它们共同形成的最大联通块的大小

可以用一个结构体记录两个联通块之间的关系

分别是两个联通块的标号(即这个联通块构成的并查集的祖先节点)

以及这两个联通块的颜色

而为了简化后面的匹配过程,要把第一个块的颜色编号改成较小的,第二个块的颜色编号改成较大的

然后对这个结构体按颜色编号的首项排序,如果首项相同就按第二项排序

这么做的目的是,让 两个相同颜色的联通块之间的关系 形成一段连续的区间,这样我们就可以省去很多时间!!!

然后每次都按关系从前到后 去合并两个颜色,统计答案,再用几个数组把并查集还原回去就行了;

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #define N 255
  5 #define maxn 1000010
  6 using namespace std;
  7
  8 int n,cnt;
  9 int a[N][N],fa[N*N],id[N][N],use[N*N],que[N*N],sum[N*N],sm[N*N];
 10 struct E{
 11     int x,y,c1,c2;
 12 }e[N*N*4];
 13 int cmp(E s1,E s2)
 14 {
 15     if(s1.c1!=s2.c1) return s1.c1<s2.c1;
 16     else return s1.c2<s2.c2;
 17 }
 18
 19 void e_add(int xx,int yy,int cc1,int cc2)
 20 {
 21     cnt++;
 22     if(cc1>cc2) swap(cc1,cc2),swap(xx,yy);
 23     e[cnt].x=xx,e[cnt].c1=cc1;
 24     e[cnt].y=yy,e[cnt].c2=cc2;
 25 }
 26 bool check(int x,int y)
 27 {
 28     if(x<1||y<1||x>n||y>n) return false;
 29     else return true;
 30 }
 31 int find_fa(int x)
 32 {
 33     int fx=x;
 34     while(fx!=fa[fx]) fx=fa[fx];
 35     while(x!=fx){
 36         int pre=fa[x];
 37         fa[x]=fx;
 38         x=pre;
 39     }
 40     return x;
 41 }
 42 void mrg1(int x,int y)
 43 {
 44     x=find_fa(x),y=find_fa(y);
 45     if(x!=y){
 46         fa[y]=x;
 47         sum[x]+=sum[y];
 48     }
 49 }
 50 void mrg2(int x,int y)
 51 {
 52     x=find_fa(x),y=find_fa(y);
 53     if(x!=y){
 54         fa[y]=x;
 55         sm[x]+=sm[y];
 56     }
 57 }
 58
 59 int main()
 60 {
 61     //freopen("data.in","r",stdin);
 62     scanf("%d",&n);
 63     for(int i=1;i<=n;i++)
 64         for(int j=1;j<=n;j++)
 65         {
 66             scanf("%d",&a[i][j]);
 67             id[i][j]=(i-1)*n+j;
 68         }
 69     for(int i=1;i<=n*n;i++) sum[i]=1,fa[i]=i;
 70     for(int i=1;i<=n;i++)
 71         for(int j=1;j<=n;j++)
 72         {
 73             if(check(i+1,j)&&a[i][j]==a[i+1][j])
 74                 mrg1(id[i][j],id[i+1][j]);
 75             if(check(i,j+1)&&a[i][j]==a[i][j+1])
 76                 mrg1(id[i][j],id[i][j+1]);
 77         }
 78     for(int i=1;i<=n*n;i++) sm[i]=sum[i];
 79     for(int i=1;i<=n;i++)
 80         for(int j=1;j<=n;j++)
 81         {
 82             if(check(i+1,j)&&a[i][j]!=a[i+1][j])
 83                 e_add(find_fa(id[i][j]),find_fa(id[i+1][j]),a[i][j],a[i+1][j]);
 84             if(check(i,j+1)&&a[i][j]!=a[i][j+1])
 85                 e_add(find_fa(id[i][j]),find_fa(id[i][j+1]),a[i][j],a[i][j+1]);
 86         }
 87     sort(e+1,e+cnt+1,cmp);
 88     int ct=0,ret=0;
 89     for(int i=1;i<=n*n;i++)
 90         ret=max(ret,sum[i]);
 91     printf("%d\n",ret);
 92     ret=0;
 93     for(int i=1;i<=cnt;i++,ct=0)
 94     {
 95         que[++ct]=e[i].x,que[++ct]=e[i].y;
 96         use[e[i].x]=use[e[i].y]=1;
 97         mrg2(e[i].x,e[i].y);  //merge
 98         while(e[i+1].c1==e[i].c1&&e[i+1].c2==e[i].c2){
 99             i++;
100             if(!use[e[i].x]) use[e[i].x]=1,que[++ct]=e[i].x;
101             if(!use[e[i].y]) use[e[i].y]=1,que[++ct]=e[i].y;
102             mrg2(e[i].x,e[i].y);
103         }
104         for(int j=1;j<=ct;j++) //calc
105             ret=max(ret,sm[que[j]]);
106         for(int j=1;j<=ct;j++) //clear
107         {
108             fa[que[j]]=que[j];
109             sm[que[j]]=sum[que[j]];
110             use[que[j]]=0;
111         }
112     }
113     printf("%d\n",ret);
114     return 0;
115 }

原文地址:https://www.cnblogs.com/guapisolo/p/9697014.html

时间: 2024-10-08 09:00:08

[USACO18OPEN] Multiplayer Moo (并查集+维护并查集技巧)的相关文章

[Codeforces 1027 F] Session in BSU [并查集维护二分图匹配问题]

题面 传送门 思路 真是一道神奇的题目呢 题目本身可以转化为二分图匹配问题,要求右半部分选择的点的最大编号最小的一组完美匹配 注意到这里左边半部分有一个性质:每个点恰好连出两条边到右半部分 那么我们可以利用这个性质 考虑一个左边的点和它右边联通的两个点,发现这两个点只能选择一个和这个左边的点匹配 那么我们考虑把这个点点匹配的模型转化成点边匹配 我们在同一个左边点连的两个右边点之间连边,那么问题就变成了一个点和一条相邻的边匹配,求完美匹配的问题了 而这个问题,我们显然可以用并查集来很好的解决 考虑

[USACO18JAN] MooTube (并查集 -&gt; 维护连通性)

题目大意:给你一棵边权树,定义两点间距离为它们唯一路径上的最小路权,求与某点距离不大于K(k为已知)的点的数量 带权并查集维护集合内元素总数 路和问题 都按权值大到小排序,枚举问题, 建权值不小于K的边,并查集维护连通性,求集合元素内总数即可 1 #include <bits/stdc++.h> 2 #define N 200100 3 #define inf 0x3f3f3f3f 4 using namespace std; 5 6 int n,q,cnt; 7 int fa[N],f[N]

猴子大王Monkey King 左偏树+并查集维护

Description Once in a forest, there lived N aggressive monkeys. At the beginning, they each does things in its own way and none of them knows each other. But monkeys can't avoid quarrelling, and it only happens between two monkeys who does not know e

BZOJ4025 二分图 分治 并查集 二分图 并查集按秩合并 带权并查集

原文链接http://www.cnblogs.com/zhouzhendong/p/8683831.html 题目传送门 - BZOJ4025 题意 有$n$个点,有$m$条边.有$T$个时间段.其中第$i$条边连接节点$x_i,y_i$,并且在$start_i$时刻出现,在$end_i$时刻消失.问每一个时刻的图是不是二分图. $n\leq 10^5,m\leq 2\times 10^5,T\leq 10^5$ 题解 真是一道好题. 做这题我才发现我从来没写过按秩合并的并查集QAQ. 先考虑按

mongodb副本集维护

mongodb副本集维护主要工作: 1.查看副本集状态(集群状态.同步延迟.单个库的运行状态mongostate) 2.增删节点.停节点shutdown mongodb副本集集群同步机制 数据复制的目的是使数据得到最大的可用性,冗余,避免单点故障. 副本集中同一时刻只有一台服务器是可以写的,primary主库上写,从库同步数据 副本集主从复制也是异步同步的过程.slave从primary上获取日志,然后在自己身上完全顺序的执行日志记录的操作(该日志不记录查询操作,只记录更新操作).被同步的日志就

Mongodb集群部署以及集群维护命令

Mongodb集群部署以及集群维护命令 http://lipeng200819861126-126-com.iteye.com/blog/1919271 mongodb分布式集群架构及监控配置 http://freeze.blog.51cto.com/1846439/884925/ 见文中: 七.监控配置:      早在去年已经出现MongoDB和Redis的Cacti模板,使用它,你可以对你的MongoDB和Redis服务进行流量监控.cacti的模板一直在更新,若企业已经用到nosql这种

Hadoop2.0集群、Hbase集群、Zookeeper集群、Hive工具、Sqoop工具、Flume工具搭建总结

实验开发环境所用软件: [[email protected] local]# ll total 320576 -rw-r--r-- 1 root root 52550402 Mar 6 10:34 apache-flume-1.6.0-bin.tar.gz drwxr-xr-x 7 root root 4096 Jul 15 10:46 flume drwxr-xr-x. 11 root root 4096 Jul 10 21:04 hadoop -rw-r--r--. 1 root root

Hadoop集群管理--保证集群平稳地运行

本篇介绍为了保证Hadoop集群平稳地运行,需要深入掌握的知识,以及一些管理监控的手段,日常维护的工作. HDFS 永久性数据结构 对于管理员来说,深入了解namenode,辅助namecode和datanode等HDFS组件如何在磁盘上组织永久性数据非常重要. 洞悉各文件的用法有助于进行故障诊断和故障检出. namenode的目录结构 namenode被格式化后,将在${dfs.namenode.name.dir}/current 目录下,产生如下的目录结构:VERSION.edits.fsi

MongoDB之分片集群与复制集

分片集群 1.1.概念 分片集群是将数据存储在多台机器上的操作,主要由查询路由mongos.分片.配置服务器组成. ●查询路由根据配置服务器上的元数据将请求分发到相应的分片上,本身不存储集群的元数据,只是缓存在内存中. ●分片用来存储数据块.数据集根据分片键将集合分割为数据块,存储在不同的分片上.在生产环境下,通常一个分片由一个复制集组成. ●配置服务器存储集群的元数据,包括数据与分片的映射关系,配置服务器一旦挂掉,集群将无法工作. 注意: ●当mongos重启时,会从配置服务器读取元数据更新自