P9073 [WC/CTS2023] 楼梯 题解
简要题意
有一块楼梯,这里指的楼梯是倒着的,正过来看上一层宽度一定小于等于这一层宽度,并且由格子组成,你需要对其进行增删和恢复某一历史版本的操作,并回答这块楼梯是否有固定格数的子楼梯。
题目分析
看到题目,平面,带修改查询,范围 \(10^9\),真是 buff 叠满了,似乎非常难以入手。
从特殊性质条件入手呢?此题给了很多特殊的性质,但是从它们相关的适用范围入手似乎都不是很好考虑,我们只好退而求其次,想想我们有什么能用的思考方式。
首先考虑归约问题,把题目中一些难以入手的问题转化为已知问题,本题中最大的难点就在于修改是对于整个平面的,况且范围过大,无法使用数据结构进行维护。
我们从较为简单的修改开始考虑,构造几个楼梯试着改一改,可以发现在这种更改信息下,貌似只是对于某个行区间的列数进行了区间增加,从这点出发,就可以把删的操作分解,看做区间推平和区间减法,即可把修改变为对于一个线段树的维护。
那最重要的询问呢,发现无处入手,我们换种思考方式,想想怎么简化问题,因为有了因数这一重要的约束条件,我们从小范围入手,看看能不能从一些特殊规律方面进行简化。先看当 \(p=q/2\) 时会发生什么,看题目所给的图,发现可行解的边界左端点构成了一个区间,这是不是我们想要的性质呢?
继续构造数据,发现虽然上述性质被否定了,但是可以发现另外一个性质,好像一个楼梯中总有一个以最右上方或左下方格子为边界的解,不要慌,想想我们能不能证明它。
边界边界,有什么性质吗,通过刚才的一通操作,再结合初看题目时的生成格,想必大家也能发现一个明显的条件,把生成格看做一个激光发射器,它垂直或平行射出的射线一定是穿透的,且它的楼梯所有的格子都在这里面,也就是说,一个子楼梯把左边界和上边界排除,一定是右边界开下边界结束(可能有点抽象,可以看图理解一下),而刚才说到的那两个格子贡献的也刚好是这两个边界!

再反过来看,两个这样的边界甚至可以确定一个唯一的子楼梯!而边界的集合也可以排出一个序列,也可以我们像刚才那样维护修改,转化成边界后,看似无用的因数一条件也可以派上用场了。
继续证明上述结论,可以发现在 \(p=q/2\) 时,子楼梯另外一个边界序号都相同,要是不是上边界就配合下面的,否则可以跟上面的配对,能继续推广吗,发现这个操作本质上是一种范围的缩小,当 \(qk=p\) 时,每次通过取中点可以排除一半的区间,进而找到答案。
上述操作也能在维护边界的线段树上二分实现,于是,我们通过常用的思维模式,解决了这道看似复杂的思维问题,希望读者在做题时,也可以多尝试用归约,分解,简化等方式进行思考(这实际上摘自《线性代数入门》中的绪论部分,感觉蛮有效的就搬过来了)。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1000000000
#define ll long long
#define N 300005
using namespace std;
ll tot,rt[N];
struct Node{
ll ls,rs,sum;
#define ls(x) tr[x].ls
#define rs(x) tr[x].rs
#define s(x) tr[x].sum
}tr[N<<5];
ll read(){
ll x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
void change(ll &x,ll l,ll r,ll p,ll val){
ll np=x;x=++tot;tr[x]=tr[np];s(x)+=val;
if(l==r) return;
ll mid=(l+r)>>1;
if(p<=mid) change(ls(x),l,mid,p,val);
else change(rs(x),mid+1,r,p,val);
s(x)=s(ls(x))+s(rs(x));
}
ll query(ll x,ll l,ll r,ll L,ll R){
if(!x || (L>=l && R<=r)) return s(x);
ll mid=(L+R)>>1;ll ans=0;
if(l<=mid) ans+=query(ls(x),l,r,L,mid);
if(r>mid) ans+=query(rs(x),l,r,mid+1,R);
return ans;
}
void clear(ll &x,ll l,ll r,ll L,ll R){
if(!x) return;if(L>=l && R<=r){x=0;return;}
ll np=x;x=++tot;tr[x]=tr[np];
ll mid=(L+R)>>1;
if(l<=mid) clear(ls(x),l,r,L,mid);
if(r>mid) clear(rs(x),l,r,mid+1,R);
s(x)=s(ls(x))+s(rs(x));
}
ll find_pos(ll x,ll l,ll r,ll val){
if(l==r) return l;
ll mid=(l+r)>>1;
if(s(rs(x))>=val) return find_pos(rs(x),mid+1,r,val);
else return find_pos(ls(x),l,mid,val-s(rs(x)));
}
ll find_x(ll x,ll val,ll l,ll r){
if(l==r) return val==1?l:-l;
ll mid=(l+r)>>1;
if(mid-l+1+s(ls(x))>=val) return find_x(ls(x),val,l,mid);
else return find_x(rs(x),val-(mid-l+1)-s(ls(x)),mid+1,r);
}
void solve(ll val,ll l,ll r,ll rt){
if(l==r-1){
ll p=find_x(rt,l*val+1,1,maxn),q=-find_x(rt,r*val+1,1,maxn);
cout<<p<<' '<<query(rt,p,maxn,1,maxn)-(val+p-q)+1<<endl;
return;
}
ll mid=(l+r)>>1;
if(find_x(rt,mid*val+1,1,maxn)>0) solve(val,mid,r,rt);
else solve(val,l,mid,rt);
}
int main(){
ll m,a,b;char opt;
m=read();
for(ll i=1;i<=m;i++){
rt[i]=rt[i-1];
cin>>opt;a=read();
if(opt=='+'){b=read();change(rt[i],1,maxn,a,b);}
else if(opt=='R') rt[i]=rt[i-a-1];
else if(opt=='-'){
b=read();
ll sum=query(rt[i],a,maxn,1,maxn);
if(sum<b){
clear(rt[i],a,maxn,1,maxn);
if(a!=1) change(rt[i],1,maxn,a-1,sum);
}
else{
ll p=find_pos(rt[i],1,maxn,b);
ll tmp=query(rt[i],p+1,maxn,1,maxn);
clear(rt[i],p+1,maxn,1,maxn);
change(rt[i],1,maxn,p,tmp-b);
if(a!=1) change(rt[i],1,maxn,a-1,b);
}
}
else if(opt=='?'){
if(s(rt[i])==0){cout<<-1<<' '<<-1<<endl;continue;}
ll k=find_pos(rt[i],1,maxn,1);
ll sum=k-1+s(rt[i]);
solve(a,0,sum/a,rt[i]);
}
}
}
P9073 [WC/CTS2023] 楼梯 题解的更多相关文章
- ACM HDU 2041--超级楼梯题解
超级楼梯 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- Hdoj 2041.超级楼梯 题解
Problem Description 有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法? Input 输入数据首先包含一个整数N,表示测试实例的个数,然后是 ...
- WC 2018 题解
WC 2018 题解 一些感受.jpg 题目难度相较前些年会相对简单一点?(FAKE.jpg 平均码量符合WC风格?(甚至更多一点 出题人良心! [WC2018] 通道 一个不知道对不对的$\log ...
- ZROI WC Round1 题解
ZROI WC Round1 题解 Problem A 题意 一个 \(n \times m\) 格子图,一个人从左上角出发,每次向右或者向下走一格,方法如下: 如果他在最下面一排,那么他会往右行走. ...
- ZROI WC Round5 题解
ZROI WC Round5 题解 Problem A 题意 给定一个长度为 \(n\) 的序列,操作是交换两个相邻的数,要求将序列变成先单调不降再单调不升,求最小操作数,注意可以完全单调不降或者完全 ...
- 【待填坑】bzoj上WC的题解
之前在bzoj上做了几道WC的题目,现在整理一下 bzoj2115 去膜拜莫队的<高斯消元解xor方程组> bzoj2597 LCT维护MST bzoj1758 分数规划+树分治+单调队列 ...
- LeetCode 题解 | 70. 爬楼梯
假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. 示例 1: 输入: 2 输出: 2 解释: 有两 ...
- 2019PKU\THU WC题解
PKU: 机试: d1t1: 考虑拓扑序的合法性,每个点的入边必须先加入.f[S]表示先出来的是S集合的点,对应边的方案数.加入x的时候,把入边方向确定,出边自然后面会确定的 2^n*n d1t2: ...
- 题解 P1255 【数楼梯】
题目链接 好吧,承认python 轻松水过 代码奉上: n = int(input()) #定义,输入 a=1 #初始的变量赋值 b=1 n-=1 #我的毒瘤的循环不得不加上这句话 if n > ...
- WC总结
去了人生中第一次全国WC,在四川绵阳南山中学举行,去了这么一次,感受颇多,不忍心白白地让时间流逝,于是写篇随笔记录一下. 全程,共计8天. [第1天] 签到,拿餐票,看了看讲义,觉得要狗带. 开营仪式 ...
随机推荐
- 【技术积累】Mysql中的SQL语言【技术篇】【四】
数据的连接与关联查询 INNER JOIN INNER JOIN是MySQL中的一种表连接操作,用于将两个或多个表中的行基于一个共同的列进行匹配,并返回匹配的结果集. 下面是一个案例,假设有两个表:o ...
- LeetCode 周赛上分之旅 #33 摩尔投票派上用场
️ 本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 [BaguTree Pro] 知识星球提问. 学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思 ...
- Asp-Net-Core学习笔记:单元测试和集成测试
前言 我在使用 AspNetCore 的这段时间内,看了很多开源项目和博客,发现各种 .Net 体系的新技术很多人都有关注和使用,但却很少有人关注测试. 测试是软件生命周期中的一个非常重要的阶段,对于 ...
- 关于win11没有gpedit.msc(本地组策略管理)的解决方案
转载自 https://blog.csdn.net/Xingchen0101/article/details/128943201 在本地部署一个bat文件 里面粘贴以下文本 pushd "% ...
- http方式内网搭建CDH6.3.2与部分组件优化
Cloudera_Manager_6.3.2安装配置文档 1. 配置准备 Cloudera Manager (简称CM)用于管理CDH6集群,可进行节点安装.配置.服务配置等,提供Web窗口界面提高了 ...
- zabbix 添加 zabbix_agentd 服务
创建服务文件 # /usr/lib/systemd/system/zabbix-agent.service [Unit] Description=Zabbix Agent After=syslog.t ...
- spring cloud微服务搭建配置中心之携程开源框架Apollo
1.Apollo(阿波罗) Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适 ...
- 华为ensp配置静态路由,三路由,三pc
华为ensp配置静态路由 目的:使pc1,pc2,pc3能相互ping通 1,tuop图的搭建 1,如图所示:先搭建好设备的通讯关系,在标记好每台设备对应的,ip地址和网关. 2,pc的网关,与ip地 ...
- vue 实现 pdf 预览功能
1 技术背景 1.1 Vue.js 简介和特点 Vue.js 是一种用于构建用户界面的渐进式框架.它具有以下特点: 易学易用:Vue.js 的 API 设计简单直观,使得开发者可以快速上手. 响应式数 ...
- AI绘画工具MJ新功能有点东西,小白也能轻松一键换装
先看最终做出来的效果 直接来干货吧.Midjourney,下面简称MJ 1.局部重绘功能来袭 就在前两天,MJ悄咪咪上线了这个被众人期待的新功能:局部重绘. 对于那些追求创新和个性化的设计师来说,局部 ...