这道题的考点比较多.

前置芝士

  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. 「JSOI2015」子集选取

    「JSOI2015」子集选取 传送门 看到这个数据范围,就知道肯定是要找规律. 如果把集合看成一个长度为 \(n\) 的 \(01\) 串, \(0\) 表示没有这个元素, \(1\) 表示有这个元素 ...

  2. RedisTemplate 获取过期时间的问题

    RedisTemplate redisTemplate; Long seconds = redisTemplate.opsForValue().getOperations().getExpire(&q ...

  3. 添加安卓端的User-Agent

    将系统换为Android即可 随机UA UA分析网站 Mozilla/5.0 (Windows NT 6. 4; WOW64) AppleWebKit/537. 36 (KHTML, like Gec ...

  4. SmartAssembly批处理用法

    在SmartAssembly.exe根目录有个SmartAssembly.com . 在命令行执行SmartAssembly.com就能看到所有的命令参数了. 用SmartAssembly.exe建好 ...

  5. Springboot学习:Thymeleaf 语法基础

    详细内容见:Thymeleaf Tutorial 中文翻译,中文文档 参考: thymeleaf官方指南 新一代Java模板引擎Thymeleaf Thymeleaf基本知识 thymeleaf总结文 ...

  6. Java判断对象是否为Null/空

    package com.taiping.test; import java.lang.reflect.Field; import java.lang.reflect.Type; /** * <p ...

  7. 洛谷P1073最优贸易(跑两遍dij)

    题目描述 CC C国有n n n个大城市和m mm 条道路,每条道路连接这 nnn个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这 mmm 条道路中有一部分为单向通行的道路,一部分为 ...

  8. 二叉树(3)AVL 树

    封装基于 BinaryTreeOperations 的 AVL 树(一种自平衡的二叉查找树). 除了提供 BinaryTreeOperations 中的部分基础接口外,增加按键的插入 和 按键或节点指 ...

  9. 五年C语言程序员,是深耕技术还是走管理?

    从进入程序员行列开始(2013年6月),到现在为止(2019年2月),已经有五年半了.    一路波折,已经从无知菜鸟走到了意识觉醒的老鸟了.    薪资变化情况如下: 2013年:2000元/月 ( ...

  10. Aery的UE4 C++游戏开发之旅(4)加载资源&创建对象

    目录 资源的硬引用 硬指针 FObjectFinder<T> / FClassFinder<T> 资源的软引用 FSoftObjectPaths.FStringAssetRef ...