C59 可持久化线段树+异或+贪心 P3293 [SCOI2016] 美味

视频链接:245 可持久化线段树+异或+贪心 P3293 [SCOI2016] 美味_哔哩哔哩_bilibili

 

 

 

 

Luogu P3293 [SCOI2016] 美味

#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();
}
const int N=200005;
#define mid ((l+r)>>1)
int n,m,mx,a[N];
int root[N],tot; //根节点,开点个数
int ls[N*25],rs[N*25],sum[N*25];
//sum:区间值的个数的前缀和

void change(int &u,int v,int l,int r,int p){ //点修
  u=++tot;
  ls[u]=ls[v]; rs[u]=rs[v]; sum[u]=sum[v]+1;
  if(l==r) return;
  if(p<=mid) change(ls[u],ls[v],l,mid,p);
  else change(rs[u],rs[v],mid+1,r,p);
}
int query(int u,int v,int l,int r,int x,int y){ //区查
  if(y<l||x>r) return 0;
  if(x<=l&&r<=y) return sum[u]-sum[v];
  return query(ls[u],ls[v],l,mid,x,y)
        +query(rs[u],rs[v],mid+1,r,x,y);
}
int main(){
  read(n);read(m);
  for(int i=1;i<=n;i++)
    read(a[i]),mx=max(a[i],mx);
  for(int i=1;i<=n;i++) 
    change(root[i],root[i-1],0,mx,a[i]);
  while(m--){
    int b,x,l,r,s=0;
    read(b);read(x);read(l);read(r);
    for(int i=18;i>=0;i--){
      int t=1<<i;
      if((b&t)&&!query(root[r],root[l-1],
                  0,mx,s-x,s-x+t-1)) s+=t;
      if(!(b&t)&&query(root[r],root[l-1],
                  0,mx,s-x+t,s-x+2*t-1)) s+=t;
    }      
    printf("%d\n",b^s);
  }
}

 

posted @ 2023-11-05 09:31  董晓  阅读(105)  评论(0编辑  收藏  举报