严格根号带修 RMQ

其实很简单,把之前随机数据的解法中维护块内数据的数据结构换成约束 RMQ,这样子复杂度 严格 单点修改 \(O(\sqrt n)\),区间查询 \(O(1)\),线性空间。

唯一的问题是常数太大了,有 \(4\) 倍常数。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2000;
const int MAXM = 20;
const int warma = 1000;
int a[1000001];
int INPUT[MAXN];
int cnt;
struct RMQ {
  int mx;
  int N, A[MAXN];
  int blockSize;
  int S[MAXN][MAXM], Pow[MAXM], Log[MAXN];
  int Belong[MAXN], Pos[MAXN];
  int Pre[MAXN], Sub[MAXN];
  int F[MAXN];
  void buildST() {
    int cur = 0, id = 1;
    Pos[0] = -1;
    for (int i = 1; i <= N; ++i) {
      S[id][0] = std::max(S[id][0], A[i]);
      Belong[i] = id;
      if (Belong[i - 1] != Belong[i])
        Pos[i] = 0;
      else
        Pos[i] = Pos[i - 1] + 1;
      if (++cur == blockSize) {
        cur = 0;
        ++id;
      }
    }
    if (N % blockSize == 0) --id;
    Pow[0] = 1;
    for (int i = 1; i < MAXM; ++i) Pow[i] = Pow[i - 1] * 2;
    for (int i = 2; i <= id; ++i) Log[i] = Log[i / 2] + 1;
    for (int i = 1; i <= Log[id]; ++i) {
      for (int j = 1; j + Pow[i] - 1 <= id; ++j) {
        S[j][i] = std::max(S[j][i - 1], S[j + Pow[i - 1]][i - 1]);
      }
    }
  }

  void buildSubPre() {
    for (int i = 1; i <= N; ++i) {
      if (Belong[i] != Belong[i - 1])
        Pre[i] = A[i];
      else
        Pre[i] = std::max(Pre[i - 1], A[i]);
    }
    for (int i = N; i >= 1; --i) {
      if (Belong[i] != Belong[i + 1])
        Sub[i] = A[i];
      else
        Sub[i] = std::max(Sub[i + 1], A[i]);
    }
  }

  void buildBlock() {
    static int S[MAXN], top;
    for (int i = 1; i <= N; ++i) {
      if (Belong[i] != Belong[i - 1])
        top = 0;
      else
        F[i] = F[i - 1];
      while (top > 0 && A[S[top]] <= A[i]) F[i] &= ~(1 << Pos[S[top--]]);
      S[++top] = i;
      F[i] |= (1 << Pos[i]);
    }
  }

  void init() {
    for(int i=1;i<=1001;i++){
            A[i]=Log[i]=Belong[i]=Pos[i]=Pre[i]=Sub[i]=F[i]=0;
    }
    for(int i=1;i<=20;i++){
    	Pow[i]=0;
	} 
	for(int i=1;i<=101;i++){
		for(int j=1;j<=11;j++){
			S[i][j]=0;
		}
	}
    mx=0;
    for (int i = 1; i <= N; ++i) A[i]=INPUT[i],mx=max(mx,A[i]);
    blockSize = max( (int)(log2(N) * 1.5),1);
    buildST();
    buildSubPre();
    buildBlock();
  }

  int queryMax(int l, int r) {
    int bl = Belong[l], br = Belong[r];
    if (bl != br) {
      int ans1 = 0;
      if (br - bl > 1) {
        int p = Log[br - bl - 1];
        ans1 = std::max(S[bl + 1][p], S[br - Pow[p]][p]);
      }
      int ans2 = std::max(Sub[l], Pre[r]);
      return std::max(ans1, ans2);
    } else {
      return A[l + __builtin_ctz(F[r] >> Pos[l])];
    }
  }
} R[MAXN];
void init(){
    for(int i=1;i<=cnt;i++){
        INPUT[i]=R[i].mx;
    }
    R[cnt+1].N=cnt;
    R[cnt+1].init();
}
int query(int l,int r){
    int bl=l/warma+1;
    l%=warma;
    if(l==0){
        bl--;
        l+=warma;   
    }
    int br=r/warma+1;
    r%=warma;
    if(r==0){
        br--;
        r+=warma;
    }
    if(bl==br){
        return R[bl].queryMax(l,r);
    }
    else if(bl+1==br){
        return max(R[bl].queryMax(l,R[bl].N),R[br].queryMax(1,r));
    }
    else{
        return max(max(R[bl].queryMax(l,R[bl].N),R[br].queryMax(1,r)),R[cnt+1].queryMax(bl+1,br-1));
    }
}
void add(int pos,int val){
    a[pos]+=val;
    int bpos=pos/warma+1;
    if(pos%warma==0){
        bpos--;
    }
    int len=0;
    for(int i=(bpos-1)*warma+1;i<=min(n,bpos*warma);i++){
    	  len++;
        INPUT[i-(bpos-1)*warma]=a[i];
    }
    R[bpos].N=len;
    R[bpos].init();
    init();
}
int n,m;
int last=1;
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        if(i%warma==0){
            R[++cnt].N=(i-last+1);
            for(int j=last;j<=i;j++){
                INPUT[j-last+1]=a[j];
            }
            R[cnt].init();
            last=i+1;
        }   
    }
    if(last<=n){
        R[++cnt].N=(n-last+1);
        for(int j=last;j<=n;j++){
                INPUT[j-last+1]=a[j];
        }
        R[cnt].init();
        last=n+1;
    }
    init();
    while(m--){
        int l,r;
        cin>>l>>r;
        cout<<query(l,r)<<'\n';
    }
  /*
  scanf("%d%d", &R.N, &M);
  R.init();
  for (int i = 0, l, r; i < M; ++i) {
    scanf("%d%d", &l, &r);
    printf("%d\n", R.queryMax(l, r));
  }
  */
  return 0;
}
posted @ 2024-02-27 18:12  ChiFAN鸭  阅读(20)  评论(0编辑  收藏  举报