P5445 [APIO2019] 路灯 题解
题目描述
给你一个 01 串,有 \(q\) 个时刻,每个时刻要么把一位取反,要么问你在过去的所有时刻中有多少个时刻 \(a\) 和 \(b-1\) 之间都为 1。
题目分析
观察题目,我们会发现可以把全为 1 的段看做一个连通块,如果两个位置在一个块内则可以互相到达,修改某个位置的值就相当于把两边的连通块合并或者分裂。
但是我们此时并非维护一个动态的连通块,而是需要知道所有时刻的信息,但是如果又把所有时刻遍历一遍会超时,考虑能不能用空间换时间,储存下所有时刻的信息方便维护。
容易观察到,维护一个连通块的目的无非是为了检查某两个点联不联通,那么我们可以抛弃连通块,转而维护两个点联通的时间数,这看似有些暴力,毕竟从空间复杂度上看 \(n^2\) 规模就已经超标了,别急,让我们先看看题目怎么操作。
对于一个询问操作自然没什么好说的,那么对于修改操作则如先前所述是将两边连通块分裂或者合并,我们把操作更改一下,记 \(l_1\),\(r_1\),\(l_2\),\(r_2\) 分别为两边连通块的左右端点,则合并操作表示所有左端点在 \([l_1,r_1]\) 内,右端点在 \([l_2,r_2]\) 的点对以后都联通,分裂相反。
注意到受影响的点实际上在平面内构成一个矩形,而询问相当于单点求值,我们能不能把修改转化成对于矩形的修改呢?当然可以,我们把对于一个点实际有效的时间段抽出来看,它实际上可以差分成一次单点加和单点减。
记当前时刻为 \(t\),只要合并时把整个矩形加上 \(q-t\),分裂时减去 \(q-t\) 即可,差分后可以使用 cdq 分治或者树套树解决,另外要注意的是查询时如果还联通,由于不考虑以后的时间,要将答案减去 \(q-t\)。
那么左右联通块如何维护呢,其实很简单,要么模仿珂朵莉树用 set 维护,要么用一颗线段树维护查询时二分即可,笔者这里使用了线段树的写法,不过细节多而且复杂度较高,还是建议使用 set 维护。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<cstring>
#define ite set<pai>::iterator
#define N 300005
using namespace std;
int read(){
int 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;
}
int tot,num,sta[N];
int a[N],rt[N];
int n,q;
struct Node{
int ls,rs,sum;
#define ls(x) tr[x].ls
#define rs(x) tr[x].rs
#define s(x) tr[x].sum
}tr[N<<8];
int query(int x,int l,int r,int L,int R){
if(!x) return 0;
if(L>=l && R<=r)return s(x);
int mid=(L+R)>>1,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 change(int &x,int p,int L,int R,int s){
if(!x) x=++tot;
s(x)+=s;if(L==R) return;
int mid=(L+R)>>1;
if(p<=mid) change(ls(x),p,L,mid,s);
else change(rs(x),p,mid+1,R,s);
}
int lowbit(int x){
return x&(-x);
}
int ask(int x,int y){
int ans=0;
while(x){
ans+=query(rt[x],1,y,1,n+2);
x-=lowbit(x);
}
return ans;
}
void add(int x,int y,int p){
while(x<=n){
change(rt[x],y,1,n+2,p);
x+=lowbit(x);
}
}
struct no{
int ls,rs,sum,l,r;
#define tls(x) t2[x].ls
#define trs(x) t2[x].rs
#define ts(x) t2[x].sum
#define tl(x) t2[x].l
#define tr(x) t2[x].r
}t2[N<<2];
void build(int &x,int l,int r){
x=++num;tl(x)=l;tr(x)=r;
if(l==r){ts(x)=sta[l];return;}
int mid=(l+r)>>1;
build(tls(x),l,mid);build(trs(x),mid+1,r);
ts(x)=ts(tls(x))+ts(trs(x));
}
void ct(int x,int p){
if(tl(x)==tr(x)) {ts(x)=sta[tl(x)];return;}
int mid=(tl(x)+tr(x))>>1;
if(p<=mid) ct(tls(x),p);
else ct(trs(x),p);
ts(x)=ts(tls(x))+ts(trs(x));
}
int qt(int x,int l,int r){
if(tl(x)>=l && tr(x)<=r) return ts(x);
int mid=(tl(x)+tr(x))>>1;int ans=0;
if(l<=mid) ans+=qt(tls(x),l,r);
if(r>mid) ans+=qt(trs(x),l,r);
return ans;
}
int findr(int x){
if(x==n) return n+1;
if(qt(1,x+1,x+1)==0) return x+1;
int l=x+1,r=n;
while(l<r){
int mid=(l+r+1)>>1;
if(qt(1,x+1,mid)==mid-x){
l=mid;
}
else r=mid-1;
}
return l+1;
}
int findl(int x){
if(x==1) return 1;
if(qt(1,x-1,x-1)==0){
return x;
}
int l=1,r=x-1;
while(l<r){
int mid=(l+r)>>1;
if(qt(1,mid,x-1)==x-1-mid+1) r=mid;
else l=mid+1;
}
return l;
}
void opti(int l,int r,int ll,int rr,int p){
add(l,r,p);add(ll+1,r,-p);add(l,rr+1,-p);add(ll+1,rr+1,p);
}
int main(){
n=read();q=read();int l,r;char ch;string s;
for(int i=1;i<=n;i++){cin>>ch;sta[i]=ch-'0';}
build(l,1,n);int st=0;
for(int i=1;i<=n;i++){
if(sta[i]==1 && sta[i-1]==0) st=i;
if(sta[i]==1 && sta[i+1]==0){
opti(st,st,i+1,i+1,q);
}
}
for(int i=1;i<=q;i++){
cin>>s;
if(s=="query"){
l=read();r=read();if(l==r){cout<<i<<endl;continue;}
int ans=ask(l,r);
if(qt(1,l,r-1)==(r-1-l+1)) ans+=i-q;
cout<<ans<<endl;
}
else{
l=read();
int ll=findl(l);
int rr=findr(l);
if(sta[l]==0)opti(ll,l+1,l,rr,q-i);
else opti(ll,l+1,l,rr,i-q);
sta[l]^=1;ct(1,l);
}
}
}
P5445 [APIO2019] 路灯 题解的更多相关文章
- P5445 [APIO2019]路灯(树套树)
P5445 [APIO2019]路灯 转化为平面上的坐标(x,y),set维护连续区间. 用树套树维护矩阵加法,单点查询. 注意维护矩阵差分的时候, $(x,y,v)$是对$(x,y)(n+1,n+1 ...
- P5445 [APIO2019]路灯
传送门· 对于询问 $(a,b)$ ,感觉一维很不好维护,考虑把询问看成平面上的一个点,坐标为 $(a,b)$ 每个坐标 $(x,y)$ 的值表示到当前 $x$ 和 $y$ 联通的时间和 考虑一个修改 ...
- APIO2019简要题解
Luogu P5444 [APIO2019]奇怪装置 看到这种题,我们肯定会想到\((x,y)\)一定有循环 我们要找到循环节的长度 推一下发现\(x\)的循环节长为\(\frac{AB}{B+1}\ ...
- 【LOJ#3146】[APIO2019]路灯(树套树)
[LOJ#3146][APIO2019]路灯(树套树) 题面 LOJ 题解 考场上因为\(\text{bridge}\)某个\(\text{subtask}\)没有判\(n=1\)的情况导致我卡了\( ...
- 洛谷 P1220 关路灯 题解
Description 有 $n$ 盏路灯,每盏路灯有坐标(单位 $m$)和功率(单位 $J$).从第 $c$ 盏路灯开始,可以向左或向右关闭路灯.速度是 $1m/s$.求所有路灯的最少耗电.输入保证 ...
- 题解-APIO2019路灯
problem \(\mathtt {loj-3146}\) 题意概要:一条直线上有 \(n+1\) 个点和 \(n\) 条道路,每条道路连通相邻两个点.在 \(q\) 个时刻内,每个时刻有如下两种操 ...
- 洛谷P1220 关路灯 题解 区间DP
题目链接:https://www.luogu.com.cn/problem/P1220 本题涉及算法:区间DP. 我们一开始要做一些初始化操作,令: \(p[i]\) 表示第i个路灯的位置: \(w[ ...
- 洛谷P1220关路灯题解
题目 此题是一个状态转移方程还算比较多的一个区间DP,这个题也能启示我们如果某个状态不能够很好地解决问题,那么不妨试试再加一维,而且如果转移顺序不确定的话,可以试试记忆化搜索,说不定就可以比较容易的写 ...
- LOJ3146 APIO2019路灯(cdq分治+树状数组)
每个时刻都形成若干段满足段内任意两点可达.将其视为若干正方形.则查询相当于求历史上某点被正方形包含的时刻数量.并且注意到每个时刻只有O(1)个正方形出现或消失,那么求出每个矩形的出现时间和消失时间,就 ...
- 2021record
2021-10-14 P2577 [ZJOI2004]午餐 2021-10-13 CF815C Karen and Supermarket(小小紫题,可笑可笑) P6748 『MdOI R3』Fall ...
随机推荐
- CS144 LAB5~LAB6
CS144 lab5~6 最后两个lab了,虽然很多大佬都说剩下的两个lab比起TCP的实现,"简直太简单了",但是我认为做这两个之前需要补充一些额外的网络知识,不然直接上手去做的 ...
- python:导入库、模块失败
一般发生在程序开始部分: from pymodbus.client.sync import ModbusSerialClient from pymodbus.payload import Binary ...
- chrome pre 自动换行
问题引出 当我想要使用chrome的打印功能生成一份关于md的pdf版本的时候发现有的代码块没有自动换行,生成的PDF没有自动换行,导致部分信息无法阅读 处理方式 把有自动换行的部分处理一下,在md文 ...
- CSS3属性 2D转换
* { margin: 0; padding: 0 } table { border-spacing: 0; border-collapse: collapse; margin: 10px auto ...
- 【pandas小技巧】--字符串转数值
字符串转数字的用途和场景很多,其中主要包括以下几个方面: 数据清洗:在进行数据处理时,经常会遇到一些数据类型不匹配的问题,比如某些列中的字符串类型被误认为是数字类型,此时需要将这些字符串类型转换为数字 ...
- python中将时间转换为时间戳
某平台url中的时间格式为时间戳,将时间变量传入url前,需要将固定格式的时间转换为时间戳.使用python中的time模块,对时间的几种格式进行转换. strptime(),将时间字符串转换成 结构 ...
- SpringBoot3集成Quartz
目录 一.简介 二.工程搭建 1.工程结构 2.依赖管理 3.数据库 4.配置文件 三.Quartz用法 1.初始化加载 2.新增任务 3.更新任务 4.暂停任务 5.恢复任务 6.执行一次 7.删除 ...
- B3612 【深进1.例1】求区间和(前缀和)
[深进1.例1]求区间和 [深进1.例1]求区间和 题目描述 给定 \(n\) 个正整数组成的数列 \(a_1, a_2, \cdots, a_n\) 和 \(m\) 个区间 \([l_i,r_i]\ ...
- AI绘画StableDiffusion实操教程:月光下的美人(含高清图片)
本教程收集于:AIGC从入门到精通教程汇总 今天继续分享AI绘画实操教程,如何用lora包生成超真实好看质感超强的人物图片. 放大高清图已放到教程包内,需要的可以自取. 出图效果: 更多图片资源访问查 ...
- 如何将现有的`Blazor`项目的主题切换写的更好看?
如何将现有的Blazor项目的主题切换写的更好看? 在现有的系统当中,我们的主题切换会比较生硬,下面我们将基于Masa Blazor实现好看的扩散主题切换的样式效果. 安装MASA.Template ...