这道题的考点比较多.

前置芝士

  1. BFS(DFS),这两种算法在这道题中并没有什么特别突出的地方,基本就是自己看心情写(本文以DFS为准,所以我心情是好是坏呢?)
  2. 连通块,可以将每一个温泉看作一个连通块,这样就变成了一个图上问题.
  3. 并查集,在判断图中元素是否相连时需要用到(具体下文会讲到).

具体做法

先用搜索将每个温泉(连通块),处理出来,并且统计出每个连通块的大小.在每次查询时只需要查询当前连通块的大小,取出最大的连通块并输出编号即可.那么,问题就在修改操作了.

当修改的点是水时只需要将当前连通块的数量-1,并且将这个位置改为土地就好了,但是当这个位置是土地时可能会将两块本不是相连的连通块连在一起,数据还是很大的,如果暴力修改肯定是会T的,这时,并查集派上用场了.当两个块因为这个点变成了温泉而相连时可以将其中一个连通块的father指向另一个连通块的father,将sum也相加这个问题就解决了,当这个位置并,没有将不同连通块连在一起时需要再开一个连通块.

细节

  1. N,M很大,不能用二维数据储存,但是NM并不大,所以对于(x,y)可以将它储存在map[(x-1)*M+y]中,但是这样储存时对于边界一定要特别判断,不然很容易就会出错.
  2. 并查集初始化时father[i]=i建议i从1到N*M赋值,或者在开出一个新的连通块时赋值.
  3. 在修改过程中可能会将同一块连通块相连,需要特别判断,勤用Find().

代码

#include<bits/stdc++.h>
#define rap(i,first,last) for(int i=first;i<=last;++i)
#define ID ((x-1)*M+y)//一时define一时爽,一直define一直爽
using namespace std;
const int maxNM=1e6+7;//N*M的最大值
const int move_x[5]={233,1,-1,0,0};//向四个方向走时用的常量数组
const int move_y[5]={233,0,0,1,-1};
int N,M;
int now=0;
int num[maxNM];//记录每个点所在的连通块的编号
int sum[maxNM];//每个连通块的大小
int _map[maxNM];//每个点的状态(是温泉还是土)
bool visit[maxNM];//在搜索时判断这个点是否到过
int father[maxNM];//记录每个点的father
int X[maxNM],Y[maxNM];
void DFS(int x,int y)//DFS遍历全图(BFS同理)
{
if(x<1||x>N||y<1||y>M)return;
if(!_map[ID])return;
if(visit[ID])return;
visit[ID]=1;
num[ID]=now;
sum[now]++;
rap(i,1,4)
DFS(x+move_x[i],y+move_y[i]);
}
int Find(int now)//并查集时用的Find函数(带压缩路径)
{
if(father[now]==now)return now;
return father[now]=Find(father[now]);
}
int cnt=0;//这个点变为温泉后会影响到的温泉数
int to[6];//影响到的温泉的编号
void Add(int nx,int ny)
{
int x=nx,y=ny;//define实在是好用
_map[ID]=1;
cnt=0;
rap(i,1,4)
{
x=nx+move_x[i];
y=ny+move_y[i];
if(x>0&&x<=N&&y>0&&y<=M)//判断边界
{
if(_map[ID])
to[++cnt]=Find(num[ID]);
}
}
x=nx;
y=ny;
if(cnt==0)//如果没有影响到其它温泉就新开一个连通块
{
sum[++now]=1;
num[ID]=now;
return;
}
sum[Find(to[1])]++;//将这个点放入其中一个连通块
num[ID]=to[1];
rap(i,2,cnt)
if(Find(to[i])!=Find(to[1]))//注意判断连通性
{
sum[to[1]]+=sum[to[i]];//连通块合并
father[to[i]]=father[to[1]];
}
}
int main()
{
scanf("%d%d",&N,&M);
char ch;
rap(x,1,N)
rap(y,1,M)
{
cin>>ch;
if(ch=='.')_map[ID]=1;
}
rap(i,1,N*M)father[i]=i;//懒得再其它地方再写
rap(x,1,N)//遍历全图,找连通块
rap(y,1,M)
if(!visit[ID]&&_map[ID])
{
now++;
DFS(x,y);
}
int Q,w,top,c,x,y;
scanf("%d",&Q);
rap(i,1,Q)
{
scanf("%d%d",&c,&w);
if(c==1)//查询
{
top=0;
rap(j,1,w)
{
scanf("%d%d",&X[j],&Y[j]);
x=X[j];
y=Y[j];
top=max(top,sum[Find(num[ID])]);//找到最大的连通块的大小
}
rap(j,1,w)
{
x=X[j];
y=Y[j];
if(sum[Find(num[ID])]==top)//输出第一个最大的连通块的编号
{
printf("%d\n",j);
break;
}
}
}
if(c==2)
{
rap(j,1,w)
{
scanf("%d%d",&X[i],&Y[i]);
x=X[i];
y=Y[i];
if(_map[ID]==0)//如果是土地就用Add
Add(X[i],Y[i]);
else//不是土地直接减去就行
{
sum[Find(num[ID])]--;
_map[ID]=0;
num[ID]=0;
}
}
}
}
}

「Luogu P3820 小D的地下温泉」的更多相关文章

  1. 基于uniapp自定义Navbar+Tabbar组件「兼容H5+小程序+App端Nvue」

    uni-app跨端自定义navbar+tabbar组件|沉浸式导航条|仿咸鱼凸起标签栏 在跨端项目开发中,uniapp是个不错的框架.采用vue.js和小程序语法结构,使得入门开发更容易.拥有非常丰富 ...

  2. 基于uni-app全端弹框组件uaPopup「兼容h5+小程序+app端|nvue」

    uniapp兼容多端自定义模态弹框组件UAPopup ua-popup 一款轻量级的uniapp自定义弹窗组件.汇集了android.ios和微信弹窗效果(msg消息.alert提示框.dialog对 ...

  3. 「Luogu P2468 [SDOI2010]粟粟的书架」

    这道题分为两个部分 Part1 前置芝士 前缀和(后缀和,二维前缀和):可以预处理一下数据. 二分查找:可以在较短的时间内找出答案. 具体做法 可以发现\(R,C\)不大,只有\(200\),于是可以 ...

  4. 「Luogu P3078 [USACO13MAR]扑克牌型Poker Hands」

    本题有\(O(N)\)的优秀做法,但是因为在考场上不一定能想到,就来分享一种\(O(N\log_2N)\)的做法.虽然有点慢,但是可以过. 前置芝士 线段树:提高组及以上必备内容,不会的同学可以学习一 ...

  5. 「Luogu P2253 好一个一中腰鼓!」

    就这道题的理论难度来说绿题是有点低了,但是这道题的实际难度来看,顶多黄题,所以建议加强数据或出数据升级版. 前置芝士 线段树:具体可以看我的另一篇文章. 具体做法 暴力的方法想必都会,所以来讲一下正解 ...

  6. luogu P1361 小M的作物

    题目链接 luogu P1361 小M的作物 题解 源汇点为A,B 向种子连边,容量为价值,每个种子能与A或B联通,考虑最小割 用建边的总流量减去最小割就是答案 相同利益的时候新建节点,由额外利益构成 ...

  7. Socket的用法——NIO包下SocketChannel的用法 ———————————————— 版权声明:本文为CSDN博主「茶_小哥」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/ycgslh/article/details/79604074

    服务端代码实现如下,其中包括一个静态内部类Handler来作为处理器,处理不同的操作.注意在遍历选择键集合时,没处理完一个操作,要将该请求在集合中移除./*模拟服务端-nio-Socket实现*/pu ...

  8. GitHub 开源的小工具「GitHub 热点速览 v.21.45」

    作者:HelloGitHub-小鱼干 Copilot 是 GitHub 官方出品的代码自动补全工具,之前使用该工具需要有一定的要求.而本周靠 2k+ star 上热点的 copilot-docs 则是 ...

  9. 获取 Windows 密码「GitHub 热点速览 v.21.28」

    作者:HelloGitHub-小鱼干 安全问题一直是 GitHub 的一大热点,因为数据安全问题诞生的各类自托管服务便是.而本周周榜上的 2 个和安全主题相关的项目,有些不同.mimikatz 是个老 ...

随机推荐

  1. ASP.NET FileUpload 上传文件类型验证

    验证的核心方法: public static bool IsAllowedExtension(FileUpload hifile) { //原方法是这样的,会提示找不到文件 //System.IO.F ...

  2. PyQt5单元格操作大全

    1.显示二维列表数据(QTableView)控件 '''显示二维列表数据(QTableView)控件数据源model需要创建一个QTableView实例和一个数据源model,然后将其两者关联 MVC ...

  3. Spring Boot 定时任务 Quartz 使用教程

    Quartz是一个完全由java编写的开源作业调度框架,他使用非常简单.本章主要讲解 Quartz在Spring Boot 中的使用. 快速集成 Quartz 介绍 Quartz 几个主要技术点 Qu ...

  4. Q - Saruman's Army POJ - 3069

    Saruman the White must lead his army along a straight path from Isengard to Helm's Deep. To keep tra ...

  5. 吴裕雄--天生自然TensorFlow2教程:手写数字问题实战

    import tensorflow as tf from tensorflow import keras from keras import Sequential,datasets, layers, ...

  6. Java面向对象编程 -1.6

    引用传递与垃圾产生分析 经过了一系列的分析之后已经确认,所有的引用传递的本质就是一场堆内存的调戏游戏.如果对于引用传递如果处理不当那么也会造成垃圾的产生, 那么本次将针对于垃圾产生的原因进行简单分析. ...

  7. PostgreSQL数据库-分页sql--offset

    select * from users order by score desc limit 3;--取成绩的前3名=====select * from users order by score des ...

  8. codeforces round#613

    A题:输出n+1: B题: 题意:就是给n个数,a人全拿,b人拿连续的子段和,如果b人比a人大于等于的话输出NO,反之输出YES 思路:最大子段和,比赛的时候忘记 ll 和 字段和不是遇到负数就重置. ...

  9. 「AT2381 [AGC015C] Nuske vs Phantom Thnook」

    题目大意 给出一个01矩阵,这个矩阵有一个特殊的性质: 对于任意两个 \(1\) 之间最多只有 \(1\) 条由 \(1\) 构成的路径.每次询问给出一个矩形范围,查询在这个范围内的联通快个数. 分析 ...

  10. oracle 基于时间错的 分区表

    我们的zabbix 监控使用 oracle 作为存储, 因此,需要创建基于 基于时间戳的分区表,在此将操作过程记录如下 1. 创建,四个zabbix 最大的表的分区表 create table his ...