首页 > 其他分享 >P5445 [APIO2019] 路灯 题解

P5445 [APIO2019] 路灯 题解

时间:2023-03-19 14:44:06浏览次数:51  
标签:APIO2019 return int 题解 mid ch ans include P5445

题目链接

题目描述

给你一个 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);
			
		}
	}
}

标签:APIO2019,return,int,题解,mid,ch,ans,include,P5445
From: https://www.cnblogs.com/eastcloud/p/17233040.html

相关文章

  • 2023.3.19 模拟赛题解
    银行取款题意在现代文明社会中,大家在诸如银行办理业务、车站买票等活动时都很文明,没有插队的现象,本着"先来先服务"的规矩。初赛已经结束了,凡凡的爸爸打算上银行去取点......
  • 【问题解决】Linux 下 VSCode IntelliSense 对 C 语言读写锁类型报错的问题
    如图下图所示,当我们想要使用C语言读写锁类型时,IntelliSense会提示如下未定义的错误:IntelliSense提示错误但是,如果忽略这些错误,直接`gcc-o`程序又没有问题。通......
  • 题解:【ARC112C】 DFS Game
    题目链接题目里面的注意点还是很多的,如果读错了题整个思路可能会一点都不对。首先是移动和选取硬币的操作是分开的,所以你移动到了一个有硬币的节点,将是你的对手获得硬币。......
  • .net6 docker部署,以及问题解决(附Dokerfile)
    搭建仓库,发布配置docker搭建私有仓库参考上文,搭建好私有仓库,成功访问http://127.0.0.1:5000/v2/_catalog之后:在VS右键=>添加=>Docker支持=>选择Linux,即可自动......
  • 蓝桥楼赛第23期-工作文件整理归类 题解
    题目描述实小楼同学平常的工作比较繁杂,经常需要处理各类文档,几天时间桌面上就累积了一堆不同类型和名称的文档,显得十分杂乱。实小楼想通过Python编写一个脚本,能够自动归......
  • Tree Depth P 题解
    TreeDepth题意\(~~~~\)对一个排列建立小根笛卡尔树,定义第\(i\)个位置的权值为其在笛卡尔树上的深度。求对于所有恰好有\(k\)个逆序对的排列,每个位置的权值和对一......
  • AGC012 题解
    chrislgjeztorAmledzaprofovelmizerdoscarmammeidhaalzengharkawymaynoxialgjeztorRupieillavasphotreywzidha[AGC012A]AtCoderGroupContest普及题......
  • [ABC245E] Wrapping Chocolate题解
    听说没人写,那就来一发。这种偏序问题大概率是要排个序的。将盒子和巧克力视为一个东西,\(c\)视为\(a\),\(d\)视为\(b\),放在一起以\(a\)为第一关键字,\(b\)为第二关键......
  • java.sql.SQLSyntaxErrorException: Table 'test.user' doesn't exist报错问题解决
    以下内容仅供自己学习使用,侵权必删在使用mubatis-plus的时候报错了以下内容java.sql.SQLSyntaxErrorException:Table'test.user'doesn'texist解决方法:2.1在......
  • CF1804F Approximate Diameter 题解
    前言在学校机房被学长推荐了这道题,听完正解后惊为天人...简化版题面给定一张无向连通图,定义直径\(d=\max(dis(i,j))\quad(i,j\inN)\),其中\(dis(i,j)\)指的是\(......