专栏文章

题解:P14268 [ROI 2015 Day2] 路灯

P14268题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@min8vurg
此快照首次捕获于
2025/12/01 22:28
3 个月前
此快照最后确认于
2025/12/01 22:28
3 个月前
查看原文
给一个完全不需要吉司机线段树的单 log\log 做法。

思路

我们定义一个区间是好的当且仅当该区间中所有的路灯当前或者曾经某时都是正常的。
假设区间 [l,r][l,r] 是好的(满足 l<rl<r),那么显然区间 [l+1,r][l+1,r] 也是好的,所以对于一个右端点 rr 来说,能够满足区间 [l,r][l,r] 是好的的 ll 是一段连续的位置。
我们设 preipre_i 表示满足区间 [l,i][l,i] 是好的最小的 ll1-1,特别的,如果不存在这样的 ll,则 prei=ipre_i=i
那么我们每次修改后的答案就是:
n(n+1)2prei\frac{n(n+1)}{2}-\sum pre_i
考虑如何用线段树维护 prepre
在我们进行区间修复路灯区间 [l,r][l,r] 时,考虑找到满足 LlL\le lrRr\le R[L,R][L,R] 中路灯都是正常的极长区间 [L,R][L,R],则对于 i[L,R]i\in[L,R],我们显然想要让 preimin{prei,L1}pre_i\gets \min\{pre_i,L-1\},可以直接用吉司机线段树维护,但是我们不会吉司机线段树,怎么办?
不难发现,preipre_i 关于 ii 在任意时刻都是单调不降的。证明是简单的,考虑如果存在 r>rr'>r,则必然存在某个时刻满足 [prer+1,r][pre_{r'}+1,r'] 中路灯都是好的,所以 prerpre_r' 必然 prer\ge pre_{r}
所以对于一次修改,一定可以等价为对一段区间进行区间赋值,则我们可以在线段树上维护 prepre 的区间 max,min\max,\min,然后进行线段树上二分,则单次修改的复杂度就是单 log\log 的。
问题只剩下怎么找到极长区间 [L,R][L,R]。对于区间修复操作,一定有 [l,r][L,R][l,r]\subseteq[L,R],所以我们可以从 ll 开始向前找最长连续的 11,从 rr 开始向后找最长连续的 11,维护方法参考线段树维护最大子段和的方法,在每个节点上记录前缀极长的 11 与后缀极长的 11。修改时区间赋值 0/10/1 即可。
综上,时间复杂度 O(nlogn)O(n\log n)

代码

CPP
#include <iostream>
#include <cstdio>
#include <algorithm>
#define ll long long
#define lc (x<<1)
#define rc ((x<<1)|1)
#define mid ((l+r)>>1)
using namespace std;
const ll N=3e5+10;
const ll INF=2147483647;
ll sum[N<<2],maxx[N<<2],minn[N<<2],tag[N<<2],a[N];
inline void push_up(ll x){
	maxx[x]=max(maxx[lc],maxx[rc]);
	minn[x]=min(minn[lc],minn[rc]);
	sum[x]=sum[lc]+sum[rc];
}
inline void push_down(ll x,ll l,ll r){
	if(tag[x]==INF) return;
	maxx[lc]=maxx[rc]=minn[lc]=minn[rc]=tag[lc]=tag[rc]=tag[x];
	sum[lc]=tag[x]*(mid-l+1),sum[rc]=tag[x]*(r-mid);
	tag[x]=INF;
}
void build(ll x,ll l,ll r){
	tag[x]=INF;
	if(l==r){sum[x]=maxx[x]=minn[x]=a[l];return;}
	build(lc,l,mid),build(rc,mid+1,r);push_up(x);
}
void chg(ll x,ll l,ll r,ll L,ll R,ll v){
	if(maxx[x]<=v) return;
	if(L<=l&&r<=R){
		if(minn[x]>=v){
			minn[x]=maxx[x]=tag[x]=v;
			sum[x]=v*(r-l+1);
			return;
		}
		else{
			push_down(x,l,r);
			chg(lc,l,mid,L,R,v);
			chg(rc,mid+1,r,L,R,v);
			push_up(x);
		}
		return;
	}
	push_down(x,l,r);
	if(L<=mid) chg(lc,l,mid,L,R,v);
	if(R>mid) chg(rc,mid+1,r,L,R,v);
	push_up(x);
}
ll query(ll x,ll l,ll r,ll L,ll R){
	if(L<=l&&r<=R) return sum[x];
	ll ret=0;push_down(x,l,r);
	if(L<=mid) ret+=query(lc,l,mid,L,R);
	if(R>mid) ret+=query(rc,mid+1,r,L,R);
	return ret;
}
ll n,q,cnt[N<<2],fug[N<<2],r1s[N<<2],l1s[N<<2];
string s;
void PU(ll x,ll l,ll r){
	cnt[x]=cnt[lc]+cnt[rc];
	if(l1s[lc]==mid-l+1) l1s[x]=l1s[lc]+l1s[rc];
	else l1s[x]=l1s[lc];
	if(r1s[rc]==r-mid) r1s[x]=r1s[rc]+r1s[lc];
	else r1s[x]=r1s[rc];
}
void PD(ll x,ll l,ll r){
	if(fug[x]==-1) return;
	fug[lc]=fug[rc]=fug[x];
	l1s[lc]=r1s[lc]=cnt[lc]=fug[x]*(mid-l+1);
	l1s[rc]=r1s[rc]=cnt[rc]=fug[x]*(r-mid);
	fug[x]=-1;
}
void B(ll x,ll l,ll r){
	fug[x]=-1;
	if(l==r){
		cnt[x]=s[l]-'0';
		l1s[x]=r1s[x]=cnt[x];
		return;
	}
	B(lc,l,mid),B(rc,mid+1,r);PU(x,l,r);
}
void modify(ll x,ll l,ll r,ll L,ll R,ll v){
	if(L<=l&&r<=R){
		fug[x]=v;
		l1s[x]=r1s[x]=cnt[x]=(r-l+1)*v;
		return;
	}
	PD(x,l,r);
	if(L<=mid) modify(lc,l,mid,L,R,v);
	if(R>mid) modify(rc,mid+1,r,L,R,v);
	PU(x,l,r);
}
ll getl(ll x,ll l,ll r,ll pos){
	if(r<=pos) return r1s[x];
	ll ret=0;PD(x,l,r);
	if(pos<=mid) return getl(lc,l,mid,pos);
	ret=getl(rc,mid+1,r,pos);
	if(ret==pos-mid) ret+=getl(lc,l,mid,pos);
	return ret;
}
ll getr(ll x,ll l,ll r,ll pos){
	if(pos<=l) return l1s[x];
	ll ret=0;PD(x,l,r);
	if(pos>mid) return getr(rc,mid+1,r,pos);
	ret=getr(lc,l,mid,pos);
	if(ret==mid-pos+1) ret+=getr(rc,mid+1,r,pos);
	return ret;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>q>>s;s=' '+s;
	for(ll i=1;i<=n;i++){
		if(s[i]=='1') a[i]=a[i-1];
		else a[i]=i;
	}
	build(1,1,n);B(1,1,n);
	ll ans=n*(n+1)/2;
	while(q--){
		ll l,r,opt;cin>>l>>r>>opt;
		if(opt==1){
			modify(1,1,n,l,r,1);
			ll lenl,lenr;
			lenl=getl(1,1,n,l);
			lenr=getr(1,1,n,r);
			l=l-lenl+1;r=r+lenr-1;
			chg(1,1,n,l,r,l-1);
		}
		else modify(1,1,n,l,r,0);
	}
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...