这道题的考点比较多.

前置芝士

  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. Vulnhub_DC7 记录

    基本步骤 经验 & 总结 对信息还是不敏感,其实也是因为对Drupal这个CMS并不熟悉,不知道哪些地方是默认的那些地方是作者修改,比如这个"DC7USER". 对Drup ...

  2. Card Game for Three

    Alice, Bob and Charlie are playing Card Game for Three, as below: At first, each of the three player ...

  3. JavaScript动画相关

    JS动画原理 通过CSS缓慢变化从而实现动画效果 获取css属性 Window.getComputedStyle()方法返回一个对象,该对象在应用活动样式表并解析这些值可能包含的任何基本计算后报告元素 ...

  4. PyCharm调试方法

    1.调试部分代码以后继续执行剩余代码,点击Resume Program:

  5. 【SSM - druid 】配置与使用

    web.xml 配置 <!-- druid的监控页面配置开始 --> <servlet> <servlet-name>StatViewServlet</ser ...

  6. TP-LINK路由器端口映射全套教程(亲测有效)

    最近想在自己的笔记本上搭建一个博客系统,方便自己写写日志,记录一些知识心得. 由于笔记本是长期放在家里的,需要在外边也能访问它,于是需要在路由器上设置一个端口映射,让在因特网上的其他电脑能访问到家里的 ...

  7. 5G新时代开启,你会选择哪家运营商?

    牌照正式发放后,5G新时代正式来临.而5G时代显然开了个好头,B站UP主"老师好我叫何同学"发布的<有多快?5G在日常使用中的真实体验>视频,引爆全网.除了仅在B站就获 ...

  8. iOS ViewController 中代码书写规范

    示例: // // CommonViewController.m // ZTBCamera // // Created by ZachRobin on 2017/8/3. // Copyright © ...

  9. 通过js检测浏览器支持的字体,从而显示支持的字体,让用户选择。

    http://www.zhangxinxu.com/wordpress/2018/02/js-detect-suppot-font-family/ 本文根据张鑫旭文章. 字体函数: var dataF ...

  10. PSP第二次总结

    项目计划总结: 姓名:李志强 日期:2017/12/06   听课 编程 阅读课本 准备考试     日总计 周日11.26               周一   100         100 周二 ...