Rmq Problem

来源:互联网 发布:cydia软件源 big 编辑:程序博客网 时间:2024/06/14 18:21

Rmq Problem

主席树 or 线段树

3339: Rmq Problem

题解:

一、主席树:

我们考虑建权值线段树,每个数字 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<<endlconst 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);    }}