题目链接

题目描述

给你一个 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] 路灯 题解的更多相关文章

  1. P5445 [APIO2019]路灯(树套树)

    P5445 [APIO2019]路灯 转化为平面上的坐标(x,y),set维护连续区间. 用树套树维护矩阵加法,单点查询. 注意维护矩阵差分的时候, $(x,y,v)$是对$(x,y)(n+1,n+1 ...

  2. P5445 [APIO2019]路灯

    传送门· 对于询问 $(a,b)$ ,感觉一维很不好维护,考虑把询问看成平面上的一个点,坐标为 $(a,b)$ 每个坐标 $(x,y)$ 的值表示到当前 $x$ 和 $y$ 联通的时间和 考虑一个修改 ...

  3. APIO2019简要题解

    Luogu P5444 [APIO2019]奇怪装置 看到这种题,我们肯定会想到\((x,y)\)一定有循环 我们要找到循环节的长度 推一下发现\(x\)的循环节长为\(\frac{AB}{B+1}\ ...

  4. 【LOJ#3146】[APIO2019]路灯(树套树)

    [LOJ#3146][APIO2019]路灯(树套树) 题面 LOJ 题解 考场上因为\(\text{bridge}\)某个\(\text{subtask}\)没有判\(n=1\)的情况导致我卡了\( ...

  5. 洛谷 P1220 关路灯 题解

    Description 有 $n$ 盏路灯,每盏路灯有坐标(单位 $m$)和功率(单位 $J$).从第 $c$ 盏路灯开始,可以向左或向右关闭路灯.速度是 $1m/s$.求所有路灯的最少耗电.输入保证 ...

  6. 题解-APIO2019路灯

    problem \(\mathtt {loj-3146}\) 题意概要:一条直线上有 \(n+1\) 个点和 \(n\) 条道路,每条道路连通相邻两个点.在 \(q\) 个时刻内,每个时刻有如下两种操 ...

  7. 洛谷P1220 关路灯 题解 区间DP

    题目链接:https://www.luogu.com.cn/problem/P1220 本题涉及算法:区间DP. 我们一开始要做一些初始化操作,令: \(p[i]\) 表示第i个路灯的位置: \(w[ ...

  8. 洛谷P1220关路灯题解

    题目 此题是一个状态转移方程还算比较多的一个区间DP,这个题也能启示我们如果某个状态不能够很好地解决问题,那么不妨试试再加一维,而且如果转移顺序不确定的话,可以试试记忆化搜索,说不定就可以比较容易的写 ...

  9. LOJ3146 APIO2019路灯(cdq分治+树状数组)

    每个时刻都形成若干段满足段内任意两点可达.将其视为若干正方形.则查询相当于求历史上某点被正方形包含的时刻数量.并且注意到每个时刻只有O(1)个正方形出现或消失,那么求出每个矩形的出现时间和消失时间,就 ...

  10. 2021record

    2021-10-14 P2577 [ZJOI2004]午餐 2021-10-13 CF815C Karen and Supermarket(小小紫题,可笑可笑) P6748 『MdOI R3』Fall ...

随机推荐

  1. 从硅谷到北京,百位AI大咖连续两天集聚讨论AI智能和实践

    全球AI大咖齐聚北京,探讨人工智能前沿!百位AI大咖倾力出席,冲向AI大浪潮! AI从业者和企业家们,一场引领未来的科技盛宴即将在北京掀起!我们荣幸地宣布,第四届"数据智能创新与实践人工智能 ...

  2. Composer 镜像原理 (1) —— 初识 Composer

    相关文章 Composer 镜像原理 (1) -- 初识 Composer Composer 镜像原理 (2) -- composer.json Composer 镜像原理 (3) -- 完结篇 何为 ...

  3. Vue Cli起别名

    vue cli 3的写法 module.exports = { configureWebpack: { resolve:{ extensions:[], alias:{ 'assets':'@/ass ...

  4. webpack dev server 与 hot module replace 提高开发效率

    通过 webpack 命令编译源代码时,如果我们对源代码进行了修改,需要重新执行命令才能看到编译后的效果. 这样在开发中非常的影响效率,如果存在一种方式,当文件被修改时,webpack 自动监听重新编 ...

  5. 好用的css3特性-动画和3d变换

    上一篇文章总结了过渡和2D变化,这一篇来总结一下动画和3D变换,动画可用的场景也很多,比如在加载的页面的时候,可以放置一个gif图,也可以自定义小动画来缓解用户等待的焦虑感,比如以下三个小圆圈转圈圈的 ...

  6. 【路由器】OpenWrt 配置使用

    目录 Web 界面 汉化 root 密码 ssh 升级 LuCI 美化 锐捷认证 MentoHUST MiniEAP 防火墙 开放端口 端口转发 IPv6 USB 安装 USB 驱动 自动挂载 Ext ...

  7. 《SQL与数据库基础》07. 约束

    目录 约束 常见约束案例 外键约束 删除/更新行为 本文以 MySQL 为例 约束 概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据. 目的:保证数据库中数据的正确性.有效性和完整性. 分 ...

  8. SQL - 5

    Smiling & Weeping ----我本不想和风讨论你,可风说可以替我去见你 第五章:SQL高级处理 5.1 窗口函数 5.1.1 窗口函数概念及基本的使用方法 窗口函数也称为OLAP ...

  9. 文心一言 VS 讯飞星火 VS chatgpt (95)-- 算法导论9.2 4题

    四.用go语言,假设用RANDOMIZED-SELECT 去选择数组 A=(3,2,9,0,7,5,4,8,6,1)的最小元素,给出能够导致 RANDOMIZED-SELECT最坏情况发生的一个划分序 ...

  10. redis基本数据类型 List

    127.0.0.1:6379> LPUSH test a (integer) 1 127.0.0.1:6379> LPUSH test b (integer) 2 127.0.0.1:63 ...