P6109 [Ynoi2009] rprmq1 做题记录

news/2025/3/25 20:47:00/文章来源:https://www.cnblogs.com/XP3301Pipi/p/18792294

P6109 [Ynoi2009] rprmq1

Description

有一个 \(n \times n\) 的矩阵 \(a\),初始全是 \(0\),有 \(m\) 次修改操作和 \(q\) 次查询操作,先进行所有修改操作,然后进行所有查询操作。

一次修改操作会给出 \(l_1,l_2,r_1,r_2,x\),代表把所有满足 \(l_1 \le i \le r_1\)\(l_2 \le j \le r_2\)\(a_{i,j}\) 元素加上一个值 \(x\)

一次查询操作会给出 \(l_1,l_2,r_1,r_2\),代表查询所有满足 \(l_1 \le i \le r_1\)\(l_2 \le j \le r_2\)\(a_{i,j}\) 元素的最大值。

\(1\leq n,m\leq 5\times 10^4\)\(1\leq q \leq 5\times 10^5\)

Solution

如果所有询问的 \(l_1\) 都是同一个值,应该怎么做?

考虑扫描线,将修改和查询的矩形拆为与 \(y\) 轴平行的线段。扫到一个查询时,其答案就对应着一段区间的历史最大值。

对于一般的情况,又该怎么做?

考虑猫树分治,将 \(x\) 轴与询问放在一起分治。

分治到 \((l,r)\) 时,我们只处理被 \(mid\) 划分为两段的询问,其余询问扔给后面处理。

此时,我们在 $mid $ 左右分别做一遍扫描线,这样就转化为所有询问的 左/右 端点都相同的情况。

每个询问至多递归 \(O(\log n)\) 层就会被某一个 \(mid\) 划分为两部分,而且得出答案的复杂度也为 $O(\log n) $,所以处理询问的复杂度为 \(O(Q\log n)\)

但是修改操作不一样。即使一个修改操作在某一层被 $mid $ 划分为两部分,仍然需要递归进两边处理,这样一个修改操作至多会进行 \(O(n)\) 次,时间复杂度为 \(O(nm\log n)\),无法接受。

注意到我们把分治树刻画出来,类似于线段树,一个修改操作最多会影响 \(O(\log n)\) 个节点。

如果一个修改操作完全覆盖了一个分治树上的节点,那么我们就将其作为下一层的初值处理,不再向下递归。那么处理一个修改操作的复杂度降为 \(O(\log^2 n)\),加起来就是 \(O(m\log^2 n)\)

在实现中,我们需要将操作撤销,并将历史最大值恢复到操作之前。这对应着把历史最大值全部置为当前最大值。

我们在线段树节点上增加一个延时标记 tag,表示这个节点的数据已经恢复完毕,其子树还没有恢复。

当一个节点被打上 tag 这个标记时,需要先下放其他标记,然后把这个节点的历史最大值赋值为当前最大值。

总时间复杂度为 \(O(m\log^2 n+Q \log n)\)

int n,Q1,Q2;struct Rect{int lx,ly,rx,ry,v;
};
vector<Rect> q1,q2;struct Line{int x,l,r,v,id;
};ll ans[M];bool CmpR(Line x,Line y){if(x.x!=y.x) return x.x<y.x;else if(x.id!=y.id) return x.id<y.id;else return x.v<y.v;
}bool CmpL(Line x,Line y){if(x.x!=y.x) return x.x>y.x;else if(x.id!=y.id) return x.id<y.id;else return x.v<y.v;
}struct SegTree{struct SegNode{ll val,mxv,add,mxd;bool tag;}tr[N<<3];void WorkAdd(int p,ll mxd,ll add){Ckmax(tr[p].mxv,tr[p].val+mxd);tr[p].val+=add;Ckmax(tr[p].mxd,tr[p].add+mxd);tr[p].add+=add;}void Roll(int p){WorkAdd(p<<1,tr[p].mxd,tr[p].add);WorkAdd(p<<1|1,tr[p].mxd,tr[p].add);tr[p].add=tr[p].mxd=0;tr[p].mxv=tr[p].val; tr[p].tag=1;}void Spread(int p){if(tr[p].tag) Roll(p<<1),Roll(p<<1|1),tr[p].tag=0;WorkAdd(p<<1,tr[p].mxd,tr[p].add);WorkAdd(p<<1|1,tr[p].mxd,tr[p].add);tr[p].mxd=tr[p].add=0;}void Pushup(int p){tr[p].val=max(tr[p<<1].val,tr[p<<1|1].val);tr[p].mxv=max(tr[p<<1].mxv,tr[p<<1|1].mxv); }void Update(int p,int l,int r,int L,int R,int v){if(L<=l&&r<=R) return WorkAdd(p,v,v);int mid=(l+r)>>1; Spread(p);if(L<=mid) Update(p<<1,l,mid,L,R,v);if(R>mid) Update(p<<1|1,mid+1,r,L,R,v);Pushup(p);}ll Ask(int p,int l,int r,int L,int R){if(L<=l&&r<=R) return tr[p].mxv;int mid=(l+r)>>1; ll res=0; Spread(p);if(L<=mid) Ckmax(res,Ask(p<<1,l,mid,L,R));if(R>mid) Ckmax(res,Ask(p<<1|1,mid+1,r,L,R));return res;} 
}Seg;struct Start{int l,r,v;
};void Solve(int l,int r,vector<Rect> U,vector<Rect> Q){if(Q.empty()) return;if(l==r||U.empty()){for(Rect i:Q){ll res=Seg.Ask(1,1,n,i.ly,i.ry);Ckmax(ans[i.v],res);}return;}vector<Rect> UL,UR,QL,QR;vector<Start> CL,CR;vector<Line> SL,SR;UL.reserve(U.size()),UR.reserve(U.size());CL.reserve(U.size()),CR.reserve(U.size());QL.reserve(Q.size()),QR.reserve(Q.size());int mid=(l+r)>>1;for(Rect i:Q){if(i.rx<=mid) QL.push_back(i);else if(i.lx>=mid+1) QR.push_back(i);else{SL.push_back({i.lx,i.ly,i.ry,0,i.v});SR.push_back({i.rx,i.ly,i.ry,0,i.v});}}for(Rect i:U){if(i.rx<=mid){if(i.rx==mid&&i.lx==l) CL.push_back({i.ly,i.ry,i.v});else UL.push_back(i);SL.push_back(Line{i.rx,i.ly,i.ry,i.v,0});SL.push_back(Line{i.lx-1,i.ly,i.ry,-i.v,0});}else if(i.lx>mid){if(i.lx==mid+1&&i.rx==r) CR.push_back({i.ly,i.ry,i.v});else UR.push_back(i);SR.push_back(Line{i.lx,i.ly,i.ry,i.v,0});SR.push_back(Line{i.rx+1,i.ly,i.ry,-i.v,0});}else{if(i.lx==l) CL.push_back({i.ly,i.ry,i.v});else UL.push_back(Rect{i.lx,i.ly,mid,i.ry,i.v});if(i.rx==r) CR.push_back({i.ly,i.ry,i.v});else UR.push_back(Rect{mid+1,i.ly,i.rx,i.ry,i.v});SL.push_back({mid,i.ly,i.ry,i.v,0});SL.push_back({i.lx-1,i.ly,i.ry,-i.v,0});SR.push_back({mid+1,i.ly,i.ry,i.v,0});SR.push_back({i.rx+1,i.ly,i.ry,-i.v,0});}}sort(SL.begin(),SL.end(),CmpL);sort(SR.begin(),SR.end(),CmpR);for(Line i:SL){if(!i.id) Seg.Update(1,1,n,i.l,i.r,i.v);else Ckmax(ans[i.id],Seg.Ask(1,1,n,i.l,i.r));}Seg.Roll(1); for(Start i:CL) Seg.Update(1,1,n,i.l,i.r,i.v);Solve(l,mid,UL,QL);for(Start i:CL) Seg.Update(1,1,n,i.l,i.r,-i.v);Seg.Roll(1);for(Line i:SR){if(!i.id) Seg.Update(1,1,n,i.l,i.r,i.v);else Ckmax(ans[i.id],Seg.Ask(1,1,n,i.l,i.r));}Seg.Roll(1);for(Start i:CR) Seg.Update(1,1,n,i.l,i.r,i.v);Solve(mid+1,r,UR,QR);for(Start i:CR) Seg.Update(1,1,n,i.l,i.r,-i.v);Seg.Roll(1);
}signed main(){read(n),read(Q1),read(Q2);q1.reserve(Q1),q2.reserve(Q2);for(int i=1;i<=Q1;i++){Rect res;read(res.lx),read(res.ly);read(res.rx),read(res.ry);read(res.v);if(res.lx==1&&res.rx==n) Seg.Update(1,1,n,res.ly,res.ry,res.v);else q1.push_back(res);}for(int i=1;i<=Q2;i++){Rect res;read(res.lx),read(res.ly);read(res.rx),read(res.ry);res.v=i;q2.push_back(res);}Solve(1,n,q1,q2);for(int i=1;i<=Q2;i++) printf("%lld\n",ans[i]);return 0;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/905643.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue+leaflet示例:地图全图以及框选截图导出功能(附源码下载)

demo源码运行环境以及配置运行环境:依赖Node安装环境,demo本地Node版本:14.19.1。 运行工具:vscode或者其他工具。 配置方式:下载demo源码,vscode打开,然后顺序执行以下命令: (1)下载demo环境依赖包命令:npm i (2)启动demo命令:npm run dev (3)打包demo命令: n…

vue+leaflet示例:聚合图功能(附源码下载)

demo源码运行环境以及配置运行环境:依赖Node安装环境,demo本地Node版本:14.19.1。 运行工具:vscode或者其他工具。 配置方式:下载demo源码,vscode打开,然后顺序执行以下命令: (1)下载demo环境依赖包命令:npm i (2)启动demo命令:npm run dev (3)打包demo命令: n…

vue+leaflet示例:结合geoserver利用WFS服务实现图层新增功能(附源码下载)

demo源码运行环境以及配置运行环境:依赖Node安装环境,demo本地Node版本:14.19.1。 运行工具:vscode或者其他工具。 配置方式:下载demo源码,vscode打开,然后顺序执行以下命令: (1)下载demo环境依赖包命令:npm i (2)启动demo命令:npm run dev (3)打包demo命令: n…

vue+leaflet示例:结合geoserver利用WFS服务实现图层编辑功能(附源码下载)

demo源码运行环境以及配置运行环境:依赖Node安装环境,demo本地Node版本:14.19.1。 运行工具:vscode或者其他工具。 配置方式:下载demo源码,vscode打开,然后顺序执行以下命令: (1)下载demo环境依赖包命令:npm i (2)启动demo命令:npm run dev (3)打包demo命令: n…

IDEA使用Docker插件打包+推送+部署

前提条件:在服务器或者虚拟机中已经安装好了Docker1、确认是否安装插件2、配置SSH链接信息3、构建一个简单的SpringBootDemo工程4、编写一点测试代码 @RestController public class HelloController {@GetMapping("/hello")public String hello(){return "<…

蓝桥真题

有奖问答 这种选择导致分支可以使用递归 我个人觉得洛谷的答案错了,如果按能得到洛谷答案的代码,改成求30题对30道,最多对30道的话,得到的是0,应该把限制条件改为能计算答对10道题的方案,因为最多十道题不是不能达到10道题DFS #include <bits/stdc++.h> using name…

day:29 python接口测试——断言、封装、关联接口

一.request断言 1、if断言 代码: if wb["msg"]=="登录成功!":print("ok") else:print("no")案例:import requests s=requests.Session() url1="http://49.233.201.254:8080/cms/manage/loginJump.do" data1={userAccou…

基于光度立体的复杂结构件表面缺陷检测数据集

为解决非平面零部件缺陷检测时,高低起伏的形貌所形成的阴影或表面反光导致的误报和漏检问题,作者提出了一种基于深度学习和光度立体的新型缺陷检测技术。摘要 为解决非平面零部件缺陷检测时,高低起伏的形貌所形成的阴影或表面反光导致的误报和漏检问题,作者提出了一种基于深…

02_Redis之数据类型及操作

本文介绍redis常用数据类型和相关操作。02_Redis之数据类型及操作一、String类型及操作 是二进制安全的,可以存放任意类型的数据。 # 设置与获取值 set k1 value1 get k1# 设置key对应的值为string 类型的value。如果key已存在,返回0,nx 是 not exist 的意思 setnx k1 value…

解析四款功能强大的GIS工具箱软件

随着GIS技术的不断发展,各类专业的GIS工具箱软件不断涌现,帮助专业人士在空间数据分析、地图可视化、三维建模等方面提供强有力的支持。本文将介绍四款GIS工具箱软件,这几款软件专注于GIS切片和GIS数据处理,适用于多个领域的地理信息数据处理,能够帮助用户高效处理和可视化…

什么是「Agentic 工作流程」?丨社区来稿

摘要分享者:Richard 林旅强(RTE 开发者社区联合主理人)什么是「Agentic 工作流程」?它是一种让 AI 智能代理(Agent)更主动、更灵活、更像人的方式来处理复杂任务的系统。刚才读到了一篇言简意赅的文章(链接在文末),我想就基于以下每一张文中的图示,来说说什么是 Agen…

2025中国生命科学与医疗行业调研报告160+份汇总解读|附PDF下载

原文链接:https://tecdat.cn/?p=41106 中国生命科学与医疗行业正经历深刻变革:政策监管趋严、技术创新加速、全球化竞争加剧,企业需在不确定性中寻找增长锚点。本报告通过数据驱动的分析框架,深度解析行业现状、挑战及未来机遇,为从业者提供战略参考。 本报告汇总解读基于…