P6492 [COCI2010-2011#6] STEP

HarleyLuu發表於2020-11-04

題目描述:

給定一個長度為 n n n 的字元序列 a a a ,初始時序列中全部都是字元 L L L

q q q 次修改,每次給定一個 x x x ,若 a x a_x ax L L L ,則將 a x a_x ax 修改成 R R R,否則將 a x a_x ax 修改成 L L L

對於一個只含字元 L L L R R R 的字串 S S S,若其中不存在連續的 L L L R R R ,則稱 S S S 滿足要求。

每次修改後,請輸出當前序列 a a a 中最長的滿足要求的連續子串的長度。

輸入格式:

第一行有兩個整數,分別表示序列的長度 n n n 和修改操作的次數 q q q

接下來 q q q 行,每行一個整數,表示本次修改的位置 x x x

輸出格式:

對於每次修改操作,輸出一行一個整數表示修改 a a a 中最長的滿足要求的子串的長度。

資料規模:

對於全部的測試點,保證 1 ≤ n , q ≤ 2 × 1 0 5 , 1 ≤ x ≤ n 1\leq n,q\leq 2 \times 10^5 , 1\leq x\leq n 1n,q2×105,1xn

樣例輸入1:

6 2
2
4

樣例輸出1:

3
5

樣例輸入2:

6 5
4
1
1
2
6

樣例輸出2:

3
3
3
5
6

思路:

不難想到 L L L R R R 用 0 和 1 來表示,用線段樹來維護序列

而對於每一個結點,維護五個值 l l l r r r L a n s Lans Lans R a n s Rans Rans a n s ans ans

其中 l l l r r r 為該節點的左右端點

L a n s Lans Lans R a n s Rans Rans 為當前區間的最左、右邊開始連續的最長滿足條件的序列

ans為當前區間內的滿足要求的最長序列的長度,而每次更新後直接查詢根結點的 a n s ans ans的值

而對於 a n s ans ans的維護:

它只可能是左右兒子結點的 a n s ans ans之一的值,

即為 T [ p o s ] . a n s = m a x ( T [ p o s < < 1 ] . a n s , T [ p o s < < 1 ∣ 1 ] . a n s ) T[pos].ans = max(T[pos<<1].ans,T[pos<<1|1].ans) T[pos].ans=max(T[pos<<1].ans,T[pos<<11].ans)

而「左兒子的最右端」和「右兒子的最左端」的序列異或值為1時,

則答案還可能為 左兒子的 R a n s Rans Rans加上右兒子的 L a n s Lans Lans的值

即為 T [ p o s ] . a n s = m a x ( T [ p o s < < 1 ] . a n s , T [ p o s < < 1 ∣ 1 ] . a n s , T [ p o s < < 1 ] . R a n s + T [ p o s < < 1 ∣ 1 ] . L a n s ) T[pos].ans = max(T[pos<<1].ans,T[pos<<1|1].ans,T[pos<<1].Rans+T[pos<<1|1].Lans) T[pos].ans=max(T[pos<<1].ans,T[pos<<11].ans,T[pos<<1].Rans+T[pos<<11].Lans)

而對於 L a n s Lans Lans的維護:

若該節點的左兒子的 L a n s Lans Lans不等於它的區間長度,則該節點的 L a n s Lans Lans等於左兒子的 L a n s Lans Lans

若該節點的左兒子的 L a n s Lans Lans等於它的區間長度,則還需判斷「左兒子的最右端」和「右兒子的最左端」序列異或值

若異或值為1時,則為左兒子的 L a n s Lans Lans加上右兒子的 L a n s Lans Lans

即為: T [ p o s ] . L a n s = T [ p o s < < 1 ] . L a n s + T [ p o s < < 1 ∣ 1 ] . L a n s T[pos].Lans=T[pos<<1].Lans+T[pos<<1|1].Lans T[pos].Lans=T[pos<<1].Lans+T[pos<<11].Lans

若異或值為0時,則直接等於左兒子的 L a n s Lans Lans

即為: T [ p o s ] . L a n s = T [ p o s < < 1 ] . L a n s T[pos].Lans=T[pos<<1].Lans T[pos].Lans=T[pos<<1].Lans

對於 R a n s Rans Rans的維護同上所示

程式碼:

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 2e5+5;
struct Tree{
    int l,r;
    int Lans,Rans;
    int ans;
}T[MAXN<<2];
int arr[MAXN];
int N,Q,x;
void build(int pos,int l,int r);
void update(int pos,int x);

int main()
{
    scanf("%d%d",&N,&Q);
    build(1,1,N);
    while(Q--){
        scanf("%d",&x);
        arr[x]^=1;
        update(1,x);
        printf("%d\n",T[1].ans);
    }
}


void build(int pos,int l,int r)
{
    T[pos].l=l; T[pos].r=r;
    if(l==r){
        T[pos].ans=1;
        T[pos].Lans=T[pos].Rans=1;
        return;
    }
    int mid = (l+r)>>1;
    build(pos<<1,l,mid);
    build(pos<<1|1,mid+1,r);
    T[pos].ans=T[pos].Lans=T[pos].Rans=1;
    return;
}

void update(int pos,int x)
{
    int l=T[pos].l,r=T[pos].r;
    if(l==r) return;
    int mid = (l+r)>>1;
    if(x<=mid) update(pos<<1,x);
    else update(pos<<1|1,x);
    
    T[pos].ans=max(T[pos<<1].ans,T[pos<<1|1].ans);
    if(arr[T[pos<<1].r]^arr[T[pos<<1|1].l])
        T[pos].ans=max(T[pos].ans,T[pos<<1].Rans+T[pos<<1|1].Lans);
    if(T[pos<<1].Lans<(T[pos<<1].r-T[pos<<1].l+1))
        T[pos].Lans=T[pos<<1].Lans;
    else{
        if(arr[T[pos<<1].r]^arr[T[pos<<1|1].l])
            T[pos].Lans=T[pos<<1].Lans+T[pos<<1|1].Lans;
        else T[pos].Lans=T[pos<<1].Lans;
    }
    
    if(T[pos<<1|1].Rans<(T[pos<<1|1].r-T[pos<<1|1].l+1))
        T[pos].Rans=T[pos<<1|1].Rans;
    else{
        if(arr[T[pos<<1].r]^arr[T[pos<<1|1].l])
            T[pos].Rans=T[pos<<1|1].Rans+T[pos<<1].Rans;
        else T[pos].Rans=T[pos<<1|1].Rans;
    }
    return;
}

相關文章