C57 可持久化线段树+二分 P2839 [国家集训队] middle

视频链接:243 可持久化线段树+二分 P2839 [国家集训队] middle_哔哩哔哩_bilibili

 

 

Luogu P2839 [国家集训队] middle

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

void read(int &x){
  x=0; char c=getchar();
  while(!isdigit(c))c=getchar();
  while(isdigit(c))x=x*10+c-'0',c=getchar();
}
#define N 20010
#define mid ((l+r)>>1)
int n,Q,q[4],last;
struct A{
  int x,id; //数,下标
  bool operator<(A &t){return x<t.x;}
}a[N];
int root[N],tot; //根节点,开点个数
int ls[N*20],rs[N*20],sum[N*20],lmx[N*20],rmx[N*20];
// sum:区间和,lmx:左最大子段和,rmx:右最大子段和

void pushup(int u){ //上传
  sum[u]=sum[ls[u]]+sum[rs[u]];
  lmx[u]=max(lmx[ls[u]],lmx[rs[u]]+sum[ls[u]]);
  rmx[u]=max(rmx[rs[u]],rmx[ls[u]]+sum[rs[u]]);
}
void build(int &u,int l,int r){ //建树
  u=++tot; //动态开点
  if(l==r){lmx[u]=rmx[u]=sum[u]=1; return;}
  build(ls[u],l,mid);
  build(rs[u],mid+1,r);
  pushup(u);
}
void change(int &u,int v,int l,int r,int p,int k){ //点修
  u=++tot; //动态开点
  ls[u]=ls[v];rs[u]=rs[v];
  sum[u]=sum[v];lmx[u]=lmx[v];rmx[u]=rmx[v];
  if(l==r){lmx[u]=rmx[u]=sum[u]=k; return;}
  if(p<=mid)change(ls[u],ls[v],l,mid,p,k);
  else change(rs[u],rs[v],mid+1,r,p,k);
  pushup(u);
}
int qsum(int u,int l,int r,int x,int y){ //区间和
  if(x<=l&&r<=y) return sum[u];
  if(y<=mid) return qsum(ls[u],l,mid,x,y);
  if(x>=mid+1) return qsum(rs[u],mid+1,r,x,y);
  return qsum(ls[u],l,mid,x,mid)+qsum(rs[u],mid+1,r,mid+1,y);
} //区间和
int qlmx(int u,int l,int r,int x,int y){ //左最大子段和
  if(l>=x&&r<=y) return lmx[u];
  if(y<=mid) return qlmx(ls[u],l,mid,x,y);
  if(x>=mid+1) return qlmx(rs[u],mid+1,r,x,y);
  return max(qlmx(ls[u],l,mid,x,mid),
         qsum(ls[u],l,mid,x,mid)+qlmx(rs[u],mid+1,r,mid+1,y));
} //左最大子段和
int qrmx(int u,int l,int r,int x,int y){ //右最大子段和
  if(l>=x&&r<=y) return rmx[u];
  if(y<=mid) return qrmx(ls[u],l,mid,x,y);
  if(x>=mid+1) return qrmx(rs[u],mid+1,r,x,y);
  return max(qrmx(rs[u],mid+1,r,mid+1,y),
         qsum(rs[u],mid+1,r,mid+1,y)+qrmx(ls[u],l,mid,x,mid));
} //右最大子段和
bool check(int u,int a,int b,int c,int d){ //check
  int s=0;
  if(c-1>=b+1)s+=qsum(root[u],1,n,b+1,c-1);
  s+=qrmx(root[u],1,n,a,b);
  s+=qlmx(root[u],1,n,c,d);
  return s>=0;
} 
int main(){
  read(n);
  for(int i=1;i<=n;i++) read(a[i].x),a[i].id=i;
  sort(a+1,a+n+1);
  build(root[0],1,n);
  for(int i=1;i<=n;i++)
    change(root[i],root[i-1],1,n,a[i].id,-1);
    
  read(Q);
  while(Q--){
    read(q[0]),read(q[1]),read(q[2]),read(q[3]);
    for(int i=0;i<4;i++) q[i]=(q[i]+last)%n+1;
    sort(q,q+4);
    int l=0,r=n+1; //二分原序列的下标位置
    while(l+1<r) check(mid,q[0],q[1],q[2],q[3])?l=mid:r=mid;
    last=a[l+1].x; //让区间和变成-1的位置即答案
    printf("%d\n",last);
  }
}

 

posted @ 2023-11-01 16:19  董晓  阅读(142)  评论(0编辑  收藏  举报