1. 程式人生 > >Codeforces Round #549 (Div. 2)E(倍增處理按排列順序的上一個位置)

Codeforces Round #549 (Div. 2)E(倍增處理按排列順序的上一個位置)

倍增 pri 數組 出現 ans 是否 con https 最大

https://codeforces.com/contest/1143/problem/E

題意

p為n的一個排列,給出有m個數字的數組a,q次詢問,每次詢問a數組區間[l,r]中是否存在子序列為p的循環排列

題解

  • 預處理出值x在排列中的上一個值_p[x]
  • 從左向右掃一遍a數組,維護值x最後出現的地方\(pre[x]\),和每個位置i在排列順序下前j個數在數組中的位置\(par[i][j]\)(倍增),然後能處理出每個位置i在排列順序下前n-1個數的位置\(v[i]\)
  • 線段樹維護v數組的區間最大值,查詢區間v[l,r]>=l即存在

代碼

#include<bits/stdc++.h>
#define MAXN 200005
using namespace std;
int n,m,q,p[MAXN],par[MAXN][25],_p[MAXN],a[MAXN],v[MAXN],mx[MAXN<<2],pre[MAXN],l,r;
void build(int o,int l,int r){
    if(l==r){mx[o]=v[l];return;}
    int mid=(l+r)/2;
    build(o<<1,l,mid);build(o<<1|1,mid+1,r);
    mx[o]=max(mx[o<<1],mx[o<<1|1]);
}
int qy(int o,int l,int r,int L,int R){
    if(L<=l&&r<=R)return mx[o];
    int mid=(l+r)/2;
    int ans=0;
    if(L<=mid)ans=max(ans,qy(o<<1,l,mid,L,R));
    if(R>mid)ans=max(ans,qy(o<<1|1,mid+1,r,L,R));
    return ans;
}
int main(){
    cin>>n>>m>>q;
    for(int i=0;i<n;i++)scanf("%d",&p[i]);
    for(int i=1;i<=m;i++)scanf("%d",&a[i]);
    for(int i=0;i<n;i++)_p[p[i]]=p[(i-1+n)%n];
    for(int i=1;i<=m;i++){
        int x=pre[_p[a[i]]];
        par[i][0]=x;for(int j=1;j<=20;j++)par[i][j]=par[par[i][j-1]][j-1];
        int d=n-1,u=i;
        for(int j=20;j>=0;j--)if(d>>j&1)u=par[u][j];
        v[i]=u;
        pre[a[i]]=i;
    }
    build(1,1,m);
    while(q--){
        scanf("%d%d",&l,&r);
        if(qy(1,1,m,l,r)>=l)printf("1");
        else printf("0");
    }
}

Codeforces Round #549 (Div. 2)E(倍增處理按排列順序的上一個位置)