前置芝士:线段树上二分。
题目大意
你可以制造一个初始高度 \(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 300050int 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
*/