CF1534F2-Falling Sand (Hard Version)

1|0正题

题目链接:https://www.luogu.com.cn/problem/CF1534F2


1|1题目大意

有一个nm个网格,有的网格上有沙子,一个沙子被刷新后会下落到底并且刷新沿途中四周四连通的沙子,你可以选择一些沙子手动刷新。

现在要求第i列至少有ai个沙子下落,求至少手动刷新多少个沙子。

1n×m4×105


1|2解题思路

显然列要求的ai就是要求最下面的那ai个沙子被刷新。

手动刷新的肯定都是每一列位置最高的沙子,然后刷新关系可以表示成一张有向图,而且是平面图,那么就说明一个沙子被刷新的条件是手动刷新了某个区间中位置最高的沙子。

我们考虑求出这些区间,先建边,这样最多4nm条边,然后对于每个沙子要求区间的左端点我们从左往右从最高的沙子开始跑,然后每次走到的点标记删除,右区间就变成从右往左跑。

得到这些区间后我们转换成若干个形如区间[l,r]中必须要有一个1的限制,然后考虑dp,用单调队列优化一下即可。

时间复杂度:O(nm)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define p(x,y) ((((x)-1)*n)+(y)) using namespace std; const int N=8e5+10; struct node{ int to,next; }a[N*4]; int n,m,tot,ls[N],l[N],r[N],lim[N],f[N]; deque<int> q;vector<int> v[N];char s[N]; void addl(int x,int y){ a[++tot].to=y; a[tot].next=ls[x]; ls[x]=tot;return; } void dfsl(int x){ for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(l[y])continue; l[y]=l[x];dfsl(y); } return; } void dfsr(int x){ for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(r[y])continue; r[y]=r[x];dfsr(y); } return; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%s",s+1); for(int j=1;j<=m;j++) if(s[j]=='#') v[j].push_back(n-i+1); } for(int i=1;i<=m;i++){ if(v[i].empty())continue; for(int j=0;j<v[i].size()-1;j++){ addl(p(i,v[i][j]),p(i,v[i][j+1])); if(v[i][j+1]+1==v[i][j])addl(p(i,v[i][j+1]),p(i,v[i][j])); } for(int g=-1;g<2;g++){ if(!g||!v[i+g].size())continue; int z=0,_=0; while(z<v[i+g].size()&&v[i+g][z]>v[i][0])z++; for(int h=v[i][0];h>=1;h--){ if(_<v[i].size()-1&&h==v[i][_+1])_++; if(z<v[i+g].size()&&h==v[i+g][z]) addl(p(i,v[i][_]),p(i+g,v[i+g][z])),z++; } } } for(int i=1;i<=m;i++){ if(v[i].empty())continue; int x=p(i,v[i][0]); if(!l[x])l[x]=i,dfsl(x); } for(int i=m;i>=1;i--){ if(v[i].empty())continue; int x=p(i,v[i][0]); if(!r[x])r[x]=i,dfsr(x); } for(int i=1,x;i<=m;i++){ scanf("%d",&x); for(int j=v[i].size()-1;j>=(int)v[i].size()-x;j--) {int y=p(i,v[i][j]);lim[r[y]]=max(lim[r[y]],l[y]);} } q.push_back(0); for(int i=1;i<=m;i++){ f[i]=max(f[i],f[q.front()]+1); while(!q.empty()&&f[q.back()]>=f[i])q.pop_back(); q.push_back(i); while(!q.empty()&&q.front()<lim[i])q.pop_front(); } printf("%d\n",f[q.front()]); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/16573737.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-08-10 P7737-[NOI2021]庆典【tarjan,虚树】
2021-08-10 P5494-[模板]线段树分裂
2021-08-10 2021“MINIEYE杯”中国大学生算法设计超级联赛(7)部分题解
2021-08-10 jzoj7212-[2022省赛]染色(color)【根号分治】
点击右上角即可分享
微信分享提示