CF803G Periodic RMQ Problem
题面翻译
给你一个序列 \(a\) 让你支持
\(1\) \(l\) \(r\) \(x\) 区间赋值
\(2\) \(l\) \(r\) 询问区间最小值
我们觉得这个问题太水了,所以我们不会给你序列\(a\)
而是给你序列一个长度为 \(n\) 的序列 \(b\) ,把 \(b\) 复制粘贴 \(k\) 次就可以得到 \(a\)
\(n\le10^5,k\le10^4,q\le10^5,b_i\le10^9\)
\(1\le l\le r\le n\times k\)
样例 #1
样例输入 #1
3 1
1 2 3
3
2 1 3
1 1 2 4
2 1 3
样例输出 #1
1
3
样例 #2
样例输入 #2
3 2
1 2 3
5
2 4 4
1 4 4 5
2 4 4
1 1 6 1
2 6 6
样例输出 #2
1
5
1
分析
直接得到序列 \(a\) 是不现实的,看到询问次数正常,考虑舍弃掉一些无用的数据。
首先可以想到只保留每次询问的两个端点并离散化,对于这 \(2\times q\) 个端点做线段树。
有这样一组样例:
5 3
5 6 2 3 6
3
2 1 5
1 2 3 4
2 1 5
按照刚才的想法,保留下来的点是 \(5\, 6\, 2\, 6\) ,第一个询问结果是 \(2\) 无误,但是区间推平后的查询结果是 \(4\) 而真正答案是 \(3\)
原因就在于我们保留的时候丢失了 \(3\) 的数据,于是我们能联想到,在我们上面保留的点的基础上,相邻两个已经保留的点之间的最小值也是需要的(但不需要整段的信息,因为不会有询问只询问这一段的一半,或者是修改一半,不然这一段就会被分成两段甚至更多),所以在上面的基础之上,我们把相邻两个点之间的最小值也插入进去做线段树就没问题了。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,b,q,tot,cnt=1,all[500005<<2];
int t[500005<<2],tag[500005<<2],a[500005];
int his[500005],now[500005],pos[500005];
struct query{
int opt,l,r,x;
void in(){
cin>>opt>>l>>r;
if(opt==1)cin>>x;
all[++tot]=l,all[++tot]=r;
}
}qq[500005];
void pushup(int num){t[num]=min(t[num<<1],t[num<<1|1]);}
void pushdown(int num,int l,int r){if(tag[num]^-1)tag[num<<1]=t[num<<1]=tag[num<<1|1]=t[num<<1|1]=tag[num],tag[num]=-1;}
void build(int l,int r,int num){
tag[num]=-1;
if(l==r)t[num]=a[l];
else{
int mid=l+r>>1;
build(l,mid,num<<1),build(mid+1,r,num<<1|1);
pushup(num);
}
}
int check(int x){int y=x%n;return y?y:n;}
void update(int l,int r,int num,int x,int y,int k){
if(x>r||y<l)return;
if(x<=l&&r<=y){tag[num]=t[num]=k;return;}
pushdown(num,l,r);
int mid=l+r>>1;
update(l,mid,num<<1,x,y,k),update(mid+1,r,num<<1|1,x,y,k);
pushup(num);
}
int getmin(int l,int r,int num,int x,int y){
if(x>r||y<l)return LONG_LONG_MAX;
if(x<=l&&r<=y)return t[num];
pushdown(num,l,r);
int mid=l+r>>1;
return min(getmin(l,mid,num<<1,x,y),getmin(mid+1,r,num<<1|1,x,y));
}
int get(int l,int r){
if(r-l+1>=n)return t[1];
l=check(l),r=check(r);
return l<=r?getmin(1,n,1,l,r):min(getmin(1,n,1,1,r),getmin(1,n,1,l,n));
}
signed main(){
cin>>n>>b;
for(int i=1;i<=n;i++)cin>>a[i];
build(1,n,1);
cin>>q;
for(int i=1;i<=q;i++)qq[i].in();
sort(all+1,all+tot+1);
tot=unique(all+1,all+tot+1)-all-1;
for(int i=1;i<=q;i++){
int ql=lower_bound(all+1,all+tot+1,qq[i].l)-all;
int qr=lower_bound(all+1,all+tot+1,qq[i].r)-all;
his[ql]=a[check(qq[i].l)],his[qr]=a[check(qq[i].r)];
}
a[1]=his[1],pos[1]=1;
for(int i=1;i<tot;i++){
if(all[i]+1<=all[i+1]-1)a[++cnt]=get(all[i]+1,all[i+1]-1);
a[++cnt]=his[i+1],pos[i+1]=cnt;
}
build(1,cnt,1);
for(int i=1;i<=q;i++){
int ql=pos[lower_bound(all+1,all+tot+1,qq[i].l)-all];
int qr=pos[lower_bound(all+1,all+tot+1,qq[i].r)-all];
if(qq[i].opt==1)update(1,cnt,1,ql,qr,qq[i].x);
else cout<<getmin(1,cnt,1,ql,qr)<<endl;
}
return 0;
}

浙公网安备 33010602011771号