Qoj 14436. Robot Construction/Open Your Brain 做题记录

前置芝士:线段树上二分。

题目大意

你可以制造一个初始高度 \(h\) 在区间 \([0, d]\) 内的机器人。

现在有一条长度为 \(n\) 的路径,上面放置了一些障碍物,用数组 \(a_1, a_2, \ldots, a_n\) 描述。

  • 如果 \(a_i = 0\),表示第 \(i\) 个位置没有障碍;
  • 如果 \(a_i > 0\),表示该处有一个高度为 \(a_i\) 的障碍。

当机器人从左到右通过一段区间 \([l, r]\) 时,会依次遇到该区间内的障碍。
对于每个障碍 \(a_i\),高度变化规则如下:

  • 若当前高度 \(h < a_i\),则机器人太矮,无法碰到障碍,高度不变;
  • 若当前高度 \(h \ge a_i\),则机器人碰到障碍,高度变为 \(h' = h - a_i\)

你需要回答 \(q\) 个询问。
每个询问给出一个区间 \([l_i, r_i]\)
要求出当初始高度 \(h \in [0, d]\) 时,
机器人通过区间 \([l_i, r_i]\) 后可能达到的最大最终高度。

思路

考虑对于一个高度为 \(a_i\) 的障碍,假设你当前可以有的高度区间为 \([0,h]\),那么我们有:

  • 对于 \(h<a_i\),答案不变;
  • 对于 \(a_i \le h <2a_i\),我们会发现 \([a_i,h]\) 的区间被往下减了 \(a_i\),所以说区间就相当于变成了 \([0,a_i-1]\)
  • 对于其他的情况,相当于变成了 \([0,h-a_i]\)

我们考虑把操作离线,进行扫描线,然后计算出每个东西的值,当当前位置为某个询问的左端点时,将 \(d\) 加入线段树,然后对线段树上值域在 \([a_i,2a_i-1]\) 的区间赋值为 \(a_i-1\),对于 \([2a_i,\inf)\) 区间减 \(a_i\)。这个东西我们可以线段树上二分,然后做一做就好了。

为什么可以线段树上二分?(即为什么在线段树上的值是单调的)

首先我们注意到每次操作不会使得答案增加,所以说后面加入的数一定是不会比前面的数要小的。

时间复杂度:\(O(q \log q)\)

点击查看代码

https://qoj.ac/submission/1488506

#include<bits/stdc++.h>

#define int ll
#define pii pair<int,int> 
#define pll pair<long long,long long> 
#define ll long long
#define i128 __int128

#define mem(a,b) memset((a),(b),sizeof(a))
#define m0(a) memset((a),0,sizeof(a))
#define m1(a) memset(a,-1,sizeof(a))
#define lb(x) ((x)&-(x))
#define lc(x) ((x)<<1)
#define rc(x) (((x)<<1)|1)
#define pb(G,x) (G).push_back((x))
#define For(a,b,c) for(int a=(b);a<=(c);a++)
#define Rep(a,b,c) for(int a=(b);a>=(c);a--)
#define in1(a) a=read()
#define in2(a,b) a=read(), b=read()
#define in3(a,b,c) a=read(), b=read(), c=read()
#define in4(a,b,c,d) a=read(), b=read(), c=read(), d=read()
#define fst first 
#define scd second 
#define dbg puts("IAKIOI")

using namespace std;

int read() {
	int x=0,f=1; char c=getchar();
	for(;c<'0'||c>'9';c=getchar()) f=(c=='-'?-1:1); 
	for(;c<='9'&&c>='0';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	return x*f;
}
void write(int x) { if(x>=10) write(x/10); putchar('0'+x%10); }

const int mod = 998244353;
int qpo(int a,int b) {int res=1; for(;b;b>>=1,a=(a*a)%mod) if(b&1) res=res*a%mod; return res; }
int inv(int a) {return qpo(a,mod-2); }

#define maxn 300050

int n,q,d;
int a[maxn],ans[maxn];

struct qur {
	int idx,l,r;
}qu[maxn];
bool cmp(qur a,qur b) {
	return a.l==b.l?a.r<b.r:a.l<b.l;
}

struct SegT {
	struct Tp {
		int mn,mx,tag1,tag2;//区间覆盖 区间加
	}tr[maxn<<2];
	
	void psu(int idx) {
		tr[idx].mx=max(tr[lc(idx)].mx,tr[rc(idx)].mx);
		tr[idx].mn=min(tr[lc(idx)].mn,tr[rc(idx)].mn);
	}
	
	void stf1(int idx,int val) {
		tr[idx].mn=tr[idx].mx=tr[idx].tag1=val; tr[idx].tag2=0;
	}
	void stf2(int idx,int val) {
		tr[idx].mn+=val,tr[idx].mx+=val;
		if(tr[idx].tag1!=1e18) tr[idx].tag1+=val; 
		else tr[idx].tag2+=val;
	}
	
	void psd(int idx,int l,int r) {
		if(tr[idx].tag1==1e18&&tr[idx].tag2==0) return ;
		if(tr[idx].tag1!=1e18) {
			stf1(lc(idx),tr[idx].tag1);
			stf1(rc(idx),tr[idx].tag1);	
			tr[idx].tag1=1e18;	 tr[idx].tag2=0;
		}
		if(tr[idx].tag2) {
			stf2(lc(idx),tr[idx].tag2);
			stf2(rc(idx),tr[idx].tag2);
			tr[idx].tag2=0;
		}
	}
	
	void build(int idx,int l,int r) {
		tr[idx].mn=tr[idx].tag1=1e18;
		tr[idx].mx=-1e18;
		if(l==r) return ;
		int mid=l+r>>1;
		build(lc(idx),l,mid);
		build(rc(idx),mid+1,r);
	}
	
	void add(int idx,int l,int r,int k,int val) {
		if(l==r) return tr[idx].mn=tr[idx].mx=val,tr[idx].tag1=1e18,tr[idx].tag2=0,void();
		int mid=l+r>>1;
		psd(idx,l,r);
		if(k<=mid) add(lc(idx),l,mid,k,val);
		else add(rc(idx),mid+1,r,k,val);
		psu(idx);
	}
	
	void modi(int idx,int l,int r,int vL,int vR,int val) {
//		cerr<<idx<<' '<<l<<' '<<r<<' '<<vL<<' '<<vR<<'\n';
		
		if(tr[idx].mx<vL) return; 
		if(tr[idx].mn>vR) { 
			stf2(idx,-val-1);
			return;
		}
		if(vL<=tr[idx].mn&&tr[idx].mx<=vR) { 
			stf1(idx,val);
			return;
		}
		if(l==r) return;
		psd(idx,l,r);
		int mid=(l+r)>>1;
		modi(lc(idx),l,mid,vL,vR,val);
		modi(rc(idx),mid+1,r,vL,vR,val);
		psu(idx);
	}
	
	int query(int idx,int l,int r,int k) {
		if(l==r) return tr[idx].mx;
		int mid=l+r>>1; psd(idx,l,r);
		if(k<=mid) return query(lc(idx),l,mid,k);
		else return query(rc(idx),mid+1,r,k);
	}
}Tr;

void work() {
	in3(n,q,d);
	For(i,1,n) in1(a[i]);
	For(i,1,q) in2(qu[i].l,qu[i].r),qu[i].idx=i;
	sort(qu+1,qu+q+1,cmp);
	vector<vector<int> > ad(n+10),calc(n+10);
	For(i,1,q) ad[qu[i].l].push_back(i),calc[qu[i].r].push_back(i);
	int cnt=0; Tr.build(1,1,q);
	For(i,1,n) {
		For(x,1,ad[i].size()) cnt++,Tr.add(1,1,q,cnt,d);
//		For(x,1,q) cout<<Tr.query(1,1,q,x)<<' '; puts("\n--");
		if(a[i]>0) Tr.modi(1,1,q,a[i],2*a[i]-1,a[i]-1);
		for(auto idx:calc[i]) {
			ans[qu[idx].idx]=Tr.query(1,1,q,idx);
		}
//		For(x,1,q) cout<<Tr.query(1,1,q,x)<<' '; puts("\n----------");
	}
	For(i,1,q) cout<<ans[i]<<'\n';
}

signed main() {
//	freopen("data.in","r",stdin);
//	freopen("myans.out","w",stdout);
//	ios::sync_with_stdio(false); 
//	cin.tie(0); cout.tie(0);
	double stt=clock();
	int _=1;
//	_=read();
//	cin>>_;
	For(i,1,_) {
		work();
	}
	cerr<<"\nTotal Time is:"<<(clock()-stt)*1.0/1000<<" second(s)."<<'\n';
	return 0;
}
/*
5 3 5
0 2 6 1 3
5 5
1 5
1 3

*/
/*
7 5 10
7 6 2 5 0 1 4
1 3
1 7
4 7
2 5
4 6
*/
posted @ 2025-10-11 16:08  coding_goat_qwq  阅读(19)  评论(0)    收藏  举报