Rmq Problem
主席树 or 线段树
题解:
一、主席树:
我们考虑建权值线段树,每个数字 x 保存它最后出现的位置
这样查询[l,r],就是找第r棵主席树中第一个值 < l 的
主席树上每个区间维护当前数中,权值从 l 到 r 中最后一次出现最靠左的位置
就是相当于维护区间最小值即可
Code:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 200000*20;
const int MX_A = 200001;
int n,q;
int lch[N],rch[N],mn[N],root[N],sz;
void clone(int t,int p){
lch[t]=lch[p]; rch[t]=rch[p]; mn[t]=mn[p];
}
void insert(int &t,int p,int l,int r,int x,int d){
t=++sz; clone(t,p);
if(l!=r){
int mid=(l+r)>>1;
if(x<=mid) insert(lch[t],lch[p],l,mid,x,d);
else insert(rch[t],rch[p],mid+1,r,x,d);
mn[t]=min(mn[lch[t]],mn[rch[t]]);
}
else{ mn[t]=d; }
}
int query(int t,int l,int r,int ql){
if(l==r) return l;
int mid=(l+r)>>1;
if(mn[lch[t]]<ql) return query(lch[t],l,mid,ql);
else return query(rch[t],mid+1,r,ql);
}
int main(){
freopen("a.in","r",stdin);
scanf("%d%d",&n,&q);
int a;
for(int i=1;i<=n;i++){
scanf("%d",&a); a++;
insert(root[i],root[i-1],1,MX_A,a,i);
}
int l,r;
while(q--){
scanf("%d%d",&l,&r);
printf("%d\n",query(root[r],1,MX_A,l)-1);
}
}
二、线段树:
(抄的黄学长的)
首先按照左端点将询问排序
然后一般可以这样考虑
首先如何得到1-i的sg值呢
这个可以一开始扫一遍完成
接着考虑l-r和l+1-r的答案有何不同
显然是l-next[l]-1这一段所有sg值大于a[l]的变为a[l]
这一步如果暴力修改的话只有30分
但是修改区间我们可以想到线段树,这样就能a了
Code:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define D(x) cout<<#x<<" = "<<x<<" "
#define E cout<<endl
const int INF = 0x3f3f3f3f;
const int NO_TAG = INF;
const int N = 200005;
using namespace std;
int sg[N],mark[N],n,m,a[N],next[N],last[N];
struct Data{
int l,r,id,ans;
} q[N];
bool cmp_l(const Data &a, const Data &b){
return a.l < b.l;
}
bool cmp_id(const Data &a, const Data &b){
return a.id < b.id;
}
struct Node{
int l,r,tag;
} pool[N*4];
void pushdown(int x){
Node &t=pool[x];
if(t.tag!=NO_TAG){
pool[x*2].tag=min(pool[x*2].tag,t.tag);
pool[x*2+1].tag=min(pool[x*2+1].tag,t.tag);
t.tag=NO_TAG;
}
}
void build(int x,int l,int r){
Node &t=pool[x];
t.l=l; t.r=r; t.tag=NO_TAG;
if(l!=r){
int mid=(t.l+t.r)>>1;
build(x*2,l,mid); build(x*2+1,mid+1,r);
}
else{ t.tag=sg[l]; }
}
void setMin(int x,int ql,int qr,int d){
Node &t=pool[x];
if(ql<=t.l && t.r<=qr){ t.tag=min(t.tag,d); }
else{
int mid=(t.l+t.r)>>1;
if(ql<=mid) setMin(x*2,ql,qr,d);
if(qr>mid) setMin(x*2+1,ql,qr,d);
}
}
int query(int x,int p){
// D(x); D(p);
Node &t=pool[x];
if(t.l==t.r) return t.tag;
else{
pushdown(x);
int mid=(t.l+t.r)>>1;
if(p<=mid) return query(x*2,p);
else return query(x*2+1,p);
}
}
int main(){
freopen("a.in","r",stdin);
scanf("%d%d",&n,&m);
int mex=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
mark[a[i]]++;
if(a[i]==mex){ while(mark[mex]) mex++; }
sg[i]=mex;
// D(sg[i]); E;
}
build(1,1,n);
for(int i=n;i>=1;i--){
next[i]=last[a[i]]==0?n+1:last[a[i]]; last[a[i]]=i;
// D(next[i]); E;
}
for(int i=1;i<=m;i++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+1+m,cmp_l);
int now=1;
for(int i=1;i<=m;i++){
while(now<q[i].l){
setMin(1,now,next[now]-1,a[now]);
now++;
}
q[i].ans=query(1,q[i].r);
// D(q[i].l); D(q[i].r); D(q[i].ans); E;
}
sort(q+1,q+1+m,cmp_id);
for(int i=1;i<=m;i++){
printf("%d\n",q[i].ans);
}
}