当前位置: 首页 > news >正文

【题解】P12019 [NOISG 2025 Finals] 洪水

P12019 [NOISG 2025 Finals] 洪水

题意

给定一个 \(n\times m\) 的网格,每个格子有数字,第 \(i\)\(j\) 列的为 \(a_{i,j}\in \{0,1\}\)\(1\) 表示该格子为建筑格子,\(0\) 表示为空格子。

初始时在空格子 \((x,y)\) 放水,然后会有如下淹没规律:

  • 如果一个空格子与至少一个被淹没的格子相邻,它会被淹没。

  • 如果一个建筑格子与至少两个被淹没的格子相邻,它会被淹没。

水不会流出边界。

记最终状态时被淹没的格子数为 \(f(x,y)\)

求出 \(\displaystyle \sum_{i=1}^n \sum_{j=1}^m [a_{i,j}=0]f(i,j)\)

\(n,m\le 5000\)

题解

知识点:扫描线,线段树,单调栈,堆。

启发:

  • 特定情况下使用堆实现延迟删除。

感觉全是基本功啊,可为什么前前后后搞了了这么久呢。

一开始没用堆,用的 multiset 卡常卡了一天还没卡过去,很难受。

思考 0

  • 空格子不会被淹没,当且仅当四联通域没有被淹没的。

  • 建筑格子不会被淹没,当且仅当四联通域至多有一个被淹没的。

被淹没的格子外围,要么是边界,要么是建筑格子。

思考 1

想一想被淹没的格子组成的形状。

当淹没的格子外围有凸出时,凸出左右边包住的不会是边界,因为边界是平的,所以只能是建筑格子,而这也是不可能的,建筑格子显然也会被淹没,所以不存在凸出,同理,也不存在凹进。所以外围是平的。

可以得出重要结论:被淹没的所有格子组成的图形一定是矩形。而矩形外围一圈(不包括四个角斜向的)不是建筑格子就是边界。

考虑将边界全变为建筑格子,可以发现他们一定不会被淹没,所以可以等效。

那么矩形的上下左右边界就都是建筑格子。

思考 2

那么一个空格子的贡献就是包含它的最小矩形的面积。

考虑处理出所有矩形,在这之前,先思考其数量级,由于矩形内部一定不能存在一整行/列的建筑格子(不然就会变成两个矩形),一个矩形的任意两对边至多同时贡献到一个矩形,这个限制比较强,故其数量级大概是 \(O(nm)\) 的。

处理出两个数组 \(ha_{i,j},la_{i,j}\),分别表示如果 \((i,j)\) 是建筑格子,其向行/列增加方向最长的连续建筑格子的长度(包括自己)。

处理出所有矩形,可以先 \(O(m)\) 枚举列 \(y\) 为其左边界,然后在每一列里面枚举上下边界的 \(x\) 坐标,判定能否组成矩形,如果能就加入,判定这一步会排除矩形内一整列建筑格子的情况。

当然,这里并不能 \(O(n^2)\) 枚举,考虑两个 \(i,j(i<j)\),如果 \(la_{i,y}\le la_{j,y}\),则 \(i\) 肯定无法和后面的搭配形成矩形了,倘若组成矩形,那么第 \(j\) 行会其中形成一个一整行的建筑格子,所以肯定不合法。

这个过程可以用单调栈实现,时间复杂度 \(O(n)\),这一步会排除矩形内一整行建筑格子的情况。

思考 3

根据之前得出的,一个空格子的贡献就是包含它的最小矩形的面积,考虑扫描线,对哪一维扫都可以,动态加入/删除矩形,权值是该矩形的面积。

一下讨论的是对 \(y\) 坐标的扫描。

扫描线达到了一个消维的效果,那么问题就转变为了:

  • 维护一个长度为 \(n\) 的序列 \(a\),初始时每个位置都为 \(+\infty\),每次给出三元组 \((l,r,s)\),对每个 \(i\in [l,r]\) 执行 \(a_i\leftarrow \min(a_i,s)\),同时还需要支持随机撤销之前三元组 \((l,r,x)\) 的作用效果,单点询问 \(a_i\) 当前的值。

第一眼有一个线段树的做法,每个节点维护一个 multiset 的做法。

区间赋值时,递归到完全被操作区间的包含的节点区间时将 \(s\) 加入该节点的 multiset

查询时,顺着查询位置走线段树上的节点直到走到叶子,答案就是路径上 multiset 里的最小值。

只可惜这个做法常数太大了,卡常卡了一页还没过,于是有一个常数更小更聪明的堆做法。

每个节点开一个 pair<int,int>priority_queue,加入节点的形式是一个 pair,面积 \(s\)first,该矩形作用时间右端点为 second,查询时先不断弹出 second 小于当前扫描到的列的队头,然后取此时的队头。

此时优先队列里面可能还有超时的元素,为什么不弹呢?其实这里用到了延迟删除的思想,不弹它并不会影响答案,那就等到队头是他的时候再弹,因为时间是单调的,某个时刻超时了,那么后面所有时刻都是超时状态。

总时间复杂度 \(O(nm \log^2 n)\),虽然和 multiset 做法的复杂度相同,但是常数小了不少。

#include<bits/stdc++.h>
using namespace std;#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()#define N 5005
#define ll long longint n,m,ha[N][N],la[N][N];
int st[N],tp,a[N][N];struct rec{int l,r,s,ed;
};vector<rec>ad[N];inline void chk(int l,int r,int j){if(r-l-1<=0||ha[l+1][j-1]<r-l-1){return;}int i=j-1,ed=j+min(la[l][j],la[r][j])-1;while(ha[l+1][i+1]<r-l-1&&i<=ed){i++;}if(i>ed||i<j){return;}// cout<<"suc\n";ad[j].pb({l+1,r-1,(r-l-1)*(i-j+1),i});// cout<<l+1<<' '<<r-1<<' '<<j<<' '<<i<<' '<<"\n";
}struct segt{#define mid ((l+r)>>1)priority_queue<pr,vector<pr>,greater<pr>>q[N<<2];inline void add(int L,int R,int k,int l,int r,int d,int ed){if(L<=l&&R>=r){q[k].push({d,ed});return;}if(L<=mid){add(L,R,k*2,l,mid,d,ed);}if(R>mid){add(L,R,k*2+1,mid+1,r,d,ed);}}inline int ask(int L,int k,int l,int r,int ed){int ans=1e9;while(1){while(sz(q[k])&&q[k].top().se<ed){q[k].pop();}if(sz(q[k])){ans=min(ans,q[k].top().fi);}if(l==r){break;}if(L<=mid){r=mid;k=k*2;}else{l=mid+1;k=k*2+1;}}return ans;}#undef mid
}t;signed main(){// freopen(".in","r",stdin);// freopen(".out","w",stdout);// ios::sync_with_stdio(0);// cin.tie(0);cout.tie(0);cin>>n>>m;n+=2,m+=2;rep(i,1,n){a[i][1]=a[i][m]=1;}rep(i,1,m){a[1][i]=a[n][i]=1;}#define getchar getchar_unlockedchar c=0;rep(i,2,n-1){rep(j,2,m-1){c=getchar();while(c!='0'&&c!='1'){c=getchar();}a[i][j]=c-'0';}}per(i,1,n){per(j,1,m){if(a[i][j]){ha[i][j]=ha[i+1][j]+1;la[i][j]=la[i][j+1]+1;}}}per(j,2,m-1){tp=0;rep(i,1,n){while(tp){chk(st[tp],i,j);if(la[st[tp]][j]>la[i][j]){break;}tp--;}st[++tp]=i;}}ll ans=0;rep(j,1,m){for(rec u:ad[j]){t.add(u.l,u.r,1,1,n,u.s,u.ed);// cout<<j<<' '<<u.l<<' '<<u.r<<" add\n";}rep(i,1,n){if(a[i][j]){continue;}ans+=t.ask(i,1,1,n,j);}}cout<<ans;return 0;
}
http://www.sczhlp.com/news/828.html

相关文章:

  • pygame小游戏打飞机_2模块显示
  • tt
  • 工程建立 - LI,Yi
  • Java基础语法学习 ———— Day1
  • 阶跃星辰端到端语音模型 Step-Audio 2:深度思考+音色切换;11Labs 对话式 AI 增加 WebRTC支持丨日报
  • 子串的故事(2) - 2025“钉耙编程”中国大学生算法设计暑期联赛(2)T4 题解
  • 【比赛记录】2025CSP-S模拟赛28
  • Apereo CAS 4.1 反序列化命令执行漏洞 (复现)
  • 第十四篇
  • 《大道至简——软件工程实践者的思想》读后感
  • DE_aemmprty 题单合集(分类)
  • 假期学习
  • C++对象模型
  • 软工7.28
  • P2910 [USACO08OPEN] Clear And Present Danger S (Floyd算法)
  • 读《构建之法》:我的C/C++学习反思
  • Qt播放音频,支持进度条,设置语速,播放暂停
  • goethereum-账户 - Charlie
  • 使用监督学习训练图像聚类模型
  • java第二十八天
  • 二叉树 (动态规划)
  • 1 引言(1.1 - 1.5)
  • 支持向量机算法
  • 决策树算法
  • 逻辑回归算法
  • static关键字--main函数
  • 长文!推荐‑搜索‑广告系统评估指标与损失函数技术报告
  • 集成学习算法
  • K 近邻算法
  • CVE-2020-13945 Apache APISIX 默认密钥漏洞 (复现)