優美序列(sequence)

問題描述

Lxy養了N頭奶牛,他把N頭奶牛用1..N編號,第i頭奶牛編號爲i。爲了讓奶牛多產奶,天天早上他都會讓奶牛們排成一排作早操。奶牛們是隨機排列的。在奶牛排列中,若是一段區間[L,R]中的數從小到大排列後是連續的,他認爲這段區間是優美的。好比奶牛排列爲:(3, 1, 7, 5, 6, 4, 2),區間[3,6]是優美的,它包含4,5,6,7連續的四個數,而區間[1,3] 是不優美的。Lxy的問題是:對於給定的一個區間[L,R](1<=L<=R<=N), 他想知道,包含區間[L,R]的最短優美區間,好比區間[1,3]的最短優美區間是[1,7]。c++

輸入

第一行爲一個整數N,表示奶牛的個數。
第二行爲1到N的一個排列,表示奶牛的隊伍。
第三行爲一個整數M,表示有M個詢問。
後面有M行,每行有兩個整數L,R表示詢問區間。數組

輸出

輸出爲M行,每行兩個整數,表示包含詢問區間的最短優美區間。ui

輸入輸出樣例

樣例1

input
7
3 1 7 5 6 4 2
3
3 6
7 7
1 3
output
3 6
7 7
1 7spa

樣例2

input
10
2 1 4 3 5 6 7 10 8 9
5
2 3
3 7
4 7
4 8
7 8
output
1 4
3 7
3 7
3 10
7 10code

數據範圍

15%的數據知足: 1 <=N,M <= 15;
50%的數據知足:1 <=N,M <= 1000。
100%的數據知足:1 <=N,M <= 100000。排序

解析

爲了給出題人留面子,不讓他被罵出個題只有一種解法並且只有滿分解法,我先給個80分作法。
預處理一個數組pos[i],表示數i在原數組的位置(第幾個數)。
在詢問區間內找一個最小值和最大值,做爲新的l和r,新的l和r做爲一個詢問區間,在pos數組裏找一個最小值和最大值,他們再做爲新的l和r,造成詢問區間,在原數組尋找最小值和最大值,並再次重複剛纔的操做……
上述過程可能很無腦很中二,然而這就是模擬題意找出答案的過程。
最大值最小值用st表預處理,一共四個st表,比線段樹好寫……
那麼……
正解是分治,像歸併排序那樣。
不斷求[l,mid] [mid+1,r]的優美序列,直到分紅[mid,mid+1]
能夠證實是正確的。
事實上分治作的熟練的人可能一眼秒這道題。get

代碼

80pts

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
template<class T>
void read(T &res)
{
    res = 0;
    T f = 1;
    char cc = getchar();
    while(cc < '0' || cc > '9')
    {
        if(cc == '-') f = -1;
        cc = getchar();
    }
    while(cc >= '0' && cc <= '9')
    {
        res = res * 10 + cc - '0';
        cc = getchar();
    }
    res *= f;
}
const int maxn = 1e5 + 5;
int n,m;
int seqmin[maxn][50];
int posmin[maxn][50];
int seqmax[maxn][50];
int posmax[maxn][50];
int ansl,ansr;
void init()
{
    for(int j=1;(1<<j) <= n;j++)
    {
        for(int i=0;i+(1<<j)-1 <= n;i++)
        {
            seqmax[i][j] = max(seqmax[i][j-1],seqmax[i+(1<<(j-1))][j-1]); // 1
            seqmin[i][j] = min(seqmin[i][j-1],seqmin[i+(1<<(j-1))][j-1]); // 2
            posmax[i][j] = max(posmax[i][j-1],posmax[i+(1<<(j-1))][j-1]); // 3
            posmin[i][j] = min(posmin[i][j-1],posmin[i+(1<<(j-1))][j-1]); // 4
        }
    }
}
int query(int l,int r,int ju)
{
    int t = int(log((double)(r - l + 1)) / log(2.0));
    if(ju == 1)
        return max(seqmax[l][t],seqmax[r-(1<<t)+1][t]);
    if(ju == 2)
        return min(seqmin[l][t],seqmin[r-(1<<t)+1][t]);
    if(ju == 3)
        return max(posmax[l][t],posmax[r-(1<<t)+1][t]);
    if(ju == 4)
        return min(posmin[l][t],posmin[r-(1<<t)+1][t]);
}
void change(int inl,int inr)
{
    int templ,tempr,endl,endr;
    templ = query(inl,inr,2);
    tempr = query(inl,inr,1);
    endl = query(templ,tempr,4);
    endr = query(templ,tempr,3);
    if(endl == inl && endr == inr)
    {
        ansl = endl;
        ansr = endr;
        return;
    }
    else
        change(endl,endr);
    
}
int main()
{
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    read(n);
    for(int i=1;i<=n;i++)
        read(seqmin[i][0]),seqmax[i][0] = seqmin[i][0];
    for(int i=1;i<=n;i++)
        posmax[seqmin[i][0]][0] = i,posmin[seqmin[i][0]][0] = i;
    init();
    read(m);
    while(m--)
    {
        int l,r;
        read(l);read(r);
        change(l,r);
        printf("%d %d\n",ansl,ansr);
    }
    return 0;
}

100pts

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100005;
#define pb push_back
#define lc (o<<1)
#define mid (l+r>>1)
#define rc ((o<<1)|1)
struct ask{
    int L,num;
    bool operator <(const ask &u)const{
        return L<u.L;
    }
};
vector<ask> g[N];
multiset<ask> s;
multiset<ask> :: iterator it;
int n,a[N],p[N],mx[N*4],pos[N*4],Q;
int le,ri,w,al[N],ar[N],M,P,tag[N*4];
inline void mt(int o){
    mx[o]=max(mx[lc],mx[rc]);
    pos[o]=(mx[rc]==mx[o]?pos[rc]:pos[lc]);
}
inline void work(int o,int der){ tag[o]+=der,mx[o]+=der;}
inline void pd(int o){ if(tag[o]) work(lc,tag[o]),work(rc,tag[o]),tag[o]=0;}
void build(int o,int l,int r){
    mx[o]=r,pos[o]=r;
    if(l==r) return;
    build(lc,l,mid),build(rc,mid+1,r);
}
void update(int o,int l,int r){
    if(l>=le&&r<=ri){ work(o,w); return;}
    pd(o);
    if(le<=mid) update(lc,l,mid);
    if(ri>mid) update(rc,mid+1,r);
    mt(o);
}
void query(int o,int l,int r){
    if(l>=le&&r<=ri){ if(mx[o]>M) M=mx[o],P=pos[o]; return;}
    pd(o);
    if(ri>mid) query(rc,mid+1,r);
    if(le<=mid) query(lc,l,mid);
}
inline bool can(int cc){
    le=1,ri=it->L,M=P=0;
    query(1,1,n);
    if(M==cc){ al[it->num]=P,ar[it->num]=cc; return 1;}
    return 0;
}
inline void solve(){
    build(1,1,n),w=1;
    ask inf=(ask){233333,0};
    for(int i=1;i<=n;i++){
        for(ask x:g[i]) s.insert(x);
        ri=p[a[i]-1],le=1;
        if(ri&&ri<i) update(1,1,n);
        ri=p[a[i]+1],le=1;
        if(ri&&ri<i) update(1,1,n);
        for(;s.size();s.erase(it)){
            it=--s.lower_bound(inf);
            if(!can(i)) break;
        }
    }
}
int main(){
  freopen("sequence.in","r",stdin);
  freopen("sequence.out","w",stdout);
     
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        p[a[i]]=i;
    };
    scanf("%d",&Q);
    for(int i=1,l,r;i<=Q;i++){
        scanf("%d %d",&l,&r);
        g[r].pb((ask){l,i});
    }
    solve();
    for(int i=1;i<=Q;i++)  printf("%d %d\n",al[i],ar[i]);
    return 0;
}
相關文章
相關標籤/搜索