#RMQ,动态开点线段树#CF803G Periodic RMQ Problem
Posted lemondinosaur
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#RMQ,动态开点线段树#CF803G Periodic RMQ Problem相关的知识,希望对你有一定的参考价值。
题目
给定\\(n\\)个数,将这个数列复制\\(k\\)次得到数列\\(a\\),
对\\(a\\)满足区间赋值操作和区间最小值询问
\\(n\\leq 10^5,q\\leq 10^5,k\\leq 10^4即|a|\\leq 10^9\\)
分析
先考虑线段树的区间赋值和区间最小值询问,如果没有复制那就是基本操作,
考虑一个很大的变化就是不可能将整棵线段树完全建好,
考虑动态开点线段树,每当新开一个点时,就先赋值为最小值,
这样线段树的大小为\\(O(q\\log|a|)\\),区间赋值和区间最小值照常完成,
所以问题就转换成快速求未改动时区间最小值,这个用RMQ做就可以了,
如果该区间长度不短于\\(n\\)就直接是原来\\(n\\)个数的最小值,
否则如果这一段跨越了复制点,就维护前缀最小值和后缀最小值拼凑,
如果区间在一段内直接用RMQ
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=100011;
int f[N][17],two[17],lg[N],pre[N],suf[N],w[N<<6],lazy[N<<6],root,ls[N<<6],rs[N<<6],cnt,n,m;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed min(int a,int b){return a<b?a:b;}
inline signed RMQ(int l,int r){
rr int z=lg[r-l+1];
return min(f[l][z],f[r-two[z]+1][z]);
}
inline signed answ(int l,int r){
if (r-l+1>=n) return pre[n];
rr int posl=(l-1)/n+1,posr=(r-1)/n+1;
l-=(posl-1)*n,r-=(posr-1)*n;
return (posl==posr)?RMQ(l,r):min(suf[l],pre[r]);
}
inline void update(int &k,int l,int r,int x,int y,int z){
if (!k) w[k=++cnt]=answ(l,r);
if (l==x&&r==y) {w[k]=lazy[k]=z; return;}
rr int mid=(l+r)>>1;
if (lazy[k]){
if (!ls[k]) ls[k]=++cnt;
if (!rs[k]) rs[k]=++cnt;
w[ls[k]]=lazy[ls[k]]=lazy[k],
w[rs[k]]=lazy[rs[k]]=lazy[k],
lazy[k]=0;
}
if (y<=mid){
if (!rs[k]) w[rs[k]=++cnt]=answ(mid+1,r);
update(ls[k],l,mid,x,y,z);
}
else if (x>mid){
if (!ls[k]) w[ls[k]=++cnt]=answ(l,mid);
update(rs[k],mid+1,r,x,y,z);
}
else update(ls[k],l,mid,x,mid,z),update(rs[k],mid+1,r,mid+1,y,z);
w[k]=min(w[ls[k]],w[rs[k]]);
}
inline signed query(int &k,int l,int r,int x,int y){
if (!k) w[k=++cnt]=answ(l,r);
if (l==x&&r==y) return w[k];
rr int mid=(l+r)>>1;
if (lazy[k]){
if (!ls[k]) ls[k]=++cnt;
if (!rs[k]) rs[k]=++cnt;
w[ls[k]]=lazy[ls[k]]=lazy[k],
w[rs[k]]=lazy[rs[k]]=lazy[k],
lazy[k]=0;
}
if (y<=mid) return query(ls[k],l,mid,x,y);
else if (x>mid) return query(rs[k],mid+1,r,x,y);
else return min(query(ls[k],l,mid,x,mid),query(rs[k],mid+1,r,mid+1,y));
}
signed main(){
n=iut(),m=iut(),lg[0]=-1,two[0]=1,pre[0]=suf[n+1]=1e9+7;
for (rr int i=1;i<17;++i) two[i]=two[i-1]<<1;
for (rr int i=1;i<=n;++i) f[i][0]=iut(),lg[i]=lg[i>>1]+1;
for (rr int i=1;i<=n;++i) pre[i]=min(pre[i-1],f[i][0]);
for (rr int i=n;i>=1;--i) suf[i]=min(suf[i+1],f[i][0]);
for (rr int j=1;j<=lg[n];++j)
for (rr int i=1;i+two[j]-1<=n;++i)
f[i][j]=min(f[i][j-1],f[i+two[j-1]][j-1]);
for (rr int T=iut();T;--T){
rr int opt=iut(),l=iut(),r=iut();
if (opt==1) update(root,1,n*m,l,r,iut());
else print(query(root,1,n*m,l,r)),putchar(10);
}
return 0;
}
以上是关于#RMQ,动态开点线段树#CF803G Periodic RMQ Problem的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 803G Periodic RMQ Problem ST表+动态开节点线段树
CF915E Physical Education Lessons|动态开点线段树