2018.1.25 T3 數列問題

在學校住了兩天感覺挺好的,但因爲Goseqh回家了,我也只好回家了。

我最近寫程序可能是狀態比較差,漏洞百出,各種詭異的錯誤挑不錯來。調試了好長時間這道題才調過。

【題面】

題目描述

更正,當k=0時,滿足條件的數不能爲這個數自身,即ij

輸入描述

輸出描述

樣例輸入

樣例輸出和數據範圍

【思路】

離線 + 線段樹。

我們可以出一個數組ddi=min{j:|aiaj|=k,j>i} ,若不存在滿足條件的j,令di=+ 。可以從右到左掃描當前序列,用map記錄每種數值最後一次出現(即下標最靠前一次出現)時的位置。對於每一個位置i ,有di=min(LastExist(ai+k),LastExist(aik))i 。然後再更新:LastExist(ai)=i

考慮假如每次詢問的x都等於1,那有什麼巧妙的解決問題的辦法。

我們不難發現所有的i<j,|aiaj|=k (這裏的j 實際上是di ,因爲di 一定是i右面最近的那個j),只要i和j都在1~y的範圍內,ji 就會稱爲可能的答案。我們不妨記錄一個數組b ,令bj=ji (若不存在i,bj=+ ),這樣的話我們只需要查詢b數組在1~y上的最小值就可以解決問題。因爲右邊界比左邊界更不容易進入到1~y的範圍裏,而只有這兩個邊界,同時進入範圍內纔可能對答案造成貢獻。

顯然,如果算出的最小值爲+ 那麼就說明沒有滿足條件的i和j,輸出-1就可以了。

按照相似的思路,我們可以把所有詢問讀入,按照x值(即左端點值)從大到小排序。

用線段樹維護一個支持單點修改,查詢區間最小值的,長度爲n的序列{bi} 。記錄一個L值,L值從右向左推移。L值每到達一個位置i ,就讓bdi=min(bdi,dii) 。按照預先排好的順序考慮所有詢問,每一次把L值向左推到當前詢問的x的位置,查詢min{bx,bx+1,...,by} 即爲答案。(L就相當於上上一段中的“1”,是一個固定了的起始位置)


【代碼】

其實還是蠻好寫的,但是我狀態不太好,寫錯了好多地方,好久才調試出來。

#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;

#define maxn (100000 + 10)
#define inf  (0x7f7f7f7f)

int lch[maxn], rch[maxn], msg[maxn], ncnt;//min
int lst[maxn], rst[maxn];
void build(int root, int l, int r){
    lst[root] = l; rst[root] = r;
    if(l == r){
        lch[root] = rch[root] = -1; //no son
        msg[root] = inf;
    }else{
        int mid = (l+r)/2;
        int nl = ++ncnt, nr = ++ncnt;
        build(nl, l, mid);
        build(nr, mid+1, r);
        msg[root] = min(msg[nl], msg[nr]);
        lch[root] = nl; rch[root] = nr;
    }
}

int query(int root, int l, int r){
    if(lst[root]>r || rst[root]<l) return inf;
    if(l<=lst[root] && rst[root]<=r) return msg[root];
    int nl = lch[root], nr = rch[root];
    return min(query(nl, l, r),query(nr, l, r));
}

void change(int root, int pos, int val){
    if(lst[root] == rst[root]){
        msg[root] = min(msg[root], val);
    }else{
        int mid = (lst[root] + rst[root])/2;
        if(pos <= mid){
            change(lch[root], pos, val);
        }else change(rch[root], pos, val);
        msg[root] = min(msg[lch[root]], msg[rch[root]]);
    }
}

int a[maxn], d[maxn], n, k;
map<int, int> lastp;

#define POS(X) ((X) == 0 ? inf : (X))
#define ANS(X) ((X) >= inf ? -1 : (X))

struct que{
    int l, r, t;
}qs[maxn]; int ans[maxn];

inline bool cmp(que a, que b){
    return a.l > b.l;
}

int main(){
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    scanf("%d%d", &n, &k);
    for(int i=1; i<=n; i++) scanf("%d", &a[i]);
    for(int i=n; i>=1; i--){
        d[i] = min(POS(lastp[a[i] + k]), POS(lastp[a[i] - k]));
        lastp[a[i]] = i;
    }
    int q; scanf("%d", &q);
    for(int i=1; i<=q; i++) scanf("%d%d", &qs[i].l, &qs[i].r), qs[i].t=i;
    int L = n+1, root = ++ncnt;
    build(root, 1, n);
    sort(qs+1, qs+q+1, cmp);
    for(int i=1; i<=q; i++){
        while(L > qs[i].l){
            L--;
            if(d[L] != inf) change(root, d[L], d[L]-L);
        }
        ans[qs[i].t] = ANS(query(root, qs[i].l, qs[i].r));
    }
    for(int i=1; i<=q; i++){
        printf("%d\n", ans[i]);
    }
    return 0;
}

/*
7 1
2 1 3 8 4 2 1
4
1 5
4 6
4 7
2 5
*/

其中有一個比較詭異的錯誤:我把msg[root]寫成了msg[maxn]導致它改寫了無辜的ncnt,使ncnt變成了inf。。

還有就是推動L時,好幾次把好幾個L都寫成了i,看了半天纔看出來。

2018.1.25

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章