这道题的考点比较多.

前置芝士

  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. 【Go语言系列】1.2、GO语言简介:哪些大公司正在使用Go语言

    Go语言的强项在于它适合用来开发网络并发方面的服务,比如消息推送.监控.容器等,所以在高并发的项目上大多数公司会优先选择 Golang 作为开发语言. 1.Google 这个不用多做介绍,作为开发Go ...

  2. DVWA实验之Brute Force(暴力破解)- Low

    DVWA实验之Brute Force-暴力破解- Low     这里开始DVWA的相关实验~   有关DVWA环境搭建的教程请参考: https://www.cnblogs.com/0yst3r-2 ...

  3. Jmeter在windows系统下的安装

    一.工具描述 apache jmeter是100%的java桌面应用程序,它被设计用来加载被测试软件功能特性.度量被测试软件的性能.设计jmeter的初衷是测试web应用, 后来又扩充了其它的功能.j ...

  4. CF10D LCIS 最长公共上升子序列

    题目描述 This problem differs from one which was on the online contest. The sequence a1,a2,...,an a_{1}, ...

  5. intellij idea 整合springboot和mybatis

    参考: http://blog.csdn.net/winter_chen001/article/details/77249029

  6. bootstrap-suggest-plugin input可选可输(表单) 好用的前端插件

    bootstrap-suggest-plugin          DEMO下载 1.准备:页面引入(点击下载) <link rel="stylesheet" href=&q ...

  7. Educational Codeforces Round 77 (Rated for Div. 2) - D. A Game with Traps(二分)

    题意:$m$个士兵,每个士兵都有一个灵敏度$a[i]$,起点为$0$,终点为$n + 1$,在路上有$k$个陷阱,每个陷阱有三个属性$l[i],r[i],d[i]$,$l[i]$表示陷阱的位置,如果你 ...

  8. row_number over ()排序函数

    语法: row_number () over (排序规则)  计算每一行数据在结果集的行数 select ROW_NUMBER() over (order by FSalary) as 排序 ,*  ...

  9. state thread api 查询

    state thread api 查询: http://state-threads.sourceforge.net/docs/reference.html

  10. Django继承drf的user模型的demo

    1.安装虚拟环境 #mkvirtualenv drfdemo -p python3 #pip install django #pip install djangorestframework #pip ...