【bzoj2329】[HNOI2011]括號修復

Description

一個合法的括號序列是這樣定義的:
1.空串是合法的。
2.如果字符串 S 是合法的,則(S)也是合法的。
3.如果字符串 A 和 B 是合法的,則 AB 也是合法的。

現在給你一個長度爲 N 的由‘(‘和‘)’組成的字符串,位置標號從 1 到 N。對這個字符串有下列四種操作:

Replace a b c:將[a,b]之間的所有括號改成 c。例如:假設原來的字符串爲:))())())(,那麼執行操作 Replace 2 7 ( 後原來的字符串變爲:)(((((()(。

Swap a b:將[a,b]之間的字符串翻轉。例如:假設原來的字符串爲:))())())(,那麼執行操作 Swap 3 5 後原來的字符串變爲:))))(())(。

Invert a b:將[a,b]之間的‘(’變成‘)’,‘)’變成‘(’。例如:假設原來的字符串爲:))())())(,那麼執行操作 Invert 4 8 後原來的字符串變爲:))((()(((。

Query a b:詢問[a,b]之間的字符串至少要改變多少位才能變成合法的括號序列。改變某位是指將該位的‘(’變成‘)’或‘)’變成‘(’。注意執行操作 Query 並不改變當前的括號序列。例如:假設原來的字符串爲:))())())(,那麼執行操作 Query 3 6的結果爲 2,因爲要將位置 5 的‘)’變成‘(’並將位置 6 的‘(’變成‘)’。

Input

從文件input.txt中讀入數據,輸入文件的第一行是用空格隔開的兩個正整數N和M,分別表示字符串的長度和將執行的操作個數。第二行是長度爲N的初始字符串S。接下來的M行是將依次執行的M個操作,其中操作名與操作數之間以及相鄰操作數之間均用空格隔開。30%的數據滿足N,M≤3000。100%的數據滿足N,M≤100000。

Output

輸出文件 output.txt 包含 T 行,其中 T 是輸入的將執行的 M 個操作中 Query 操作出現的次數。Query 操作的每次出現依次對應輸出文件中的一行,該行只有一個非負整數,表示執行對應 Query 操作的結果,即:所指字符串至少要改變多少位才能變成合法的括號序列。輸入數據保證問題有解。

Sample Input

4 5
((((
Replace 1 2 )
Query 1 2
Swap 2 3
Invert 3 4
Query 1 4

Sample Output

1
2

題解

能夠1A這題還是很開心的,雖然我寫了一個早上。
傳送門:http://www.cnblogs.com/oldmanren/archive/2011/11/24/2262178.html一個寫得十分清楚的題解。
簡單來說Replace,Swap和Invert都是經典的splay操作。而Query可以轉換爲區間左起最小值和右起最大值的查詢。
但是標記的下傳也並沒有那麼麻煩。考慮對一段區間進行Replace操作,那麼之前這段區間上的Swap和Invert操作的標記都會失效,我們可以直接將它們清零。那麼對於一個節點上的標記,Replace操作的標記必然是最先操作的,那麼首先將它下傳,然後Swap操作的標記和Invert操作的標記就可以任意順序下傳了。
(發現我的程序還是算蠻短的233)

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

const int N = 100000 + 10;

inline int read(){
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)) { if(c == '-') f = -1; c = getchar(); }
    while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}
int n, m;

struct Splay{
    int num, sum, _cov, _flip, _rev, siz;
    int lmx, lmn, rmx, rmn;
    Splay *fa, *ch[2];

    int d(){return fa->ch[1] == this;}
    void sc(Splay *a, int d){(ch[d] = a)->fa = this;}

    void cov(int x){
        sum = x * siz;
        num = x;
        if(x == 1)
            lmx = rmx = sum, lmn = rmn = 0;
        else
            lmn = rmn = sum, lmx = rmx = 0;
        _cov = x;
        _rev = _flip = 0;
    }
    void rev(){
        swap(lmx, rmx); swap(lmn, rmn);
        swap(ch[0], ch[1]);
        _rev ^= 1;
    }
    void flip(){
        sum *= -1;
        num *= -1;
        swap(lmx, lmn); swap(rmx, rmn);
        lmx *= -1, lmn *= -1, rmx *= -1, rmn *= -1;
        _flip ^= 1;
    }

    void pup();
    void pdw();
    Splay();
} nil[N], *rt;
Splay :: Splay(){fa = ch[0] = ch[1] = nil;}

void Splay :: pup(){
    siz = ch[0]->siz + ch[1]->siz + 1;
    sum = ch[0]->sum + ch[1]->sum + num;
    lmx = max(ch[0]->lmx, ch[0]->sum + num + ch[1]->lmx);
    lmn = min(ch[0]->lmn, ch[0]->sum + num + ch[1]->lmn);
    rmx = max(ch[1]->rmx, ch[1]->sum + num + ch[0]->rmx);
    rmn = min(ch[1]->rmn, ch[1]->sum + num + ch[0]->rmn);
}

void Splay :: pdw(){
    if(_cov){
        ch[0]->cov(_cov), ch[1]->cov(_cov);
        _cov = 0;
    }
    if(_flip){
        ch[0]->flip(), ch[1]->flip();
        _flip = 0;
    }
    if(_rev){
        ch[0]->rev(), ch[1]->rev();
        _rev = 0;
    }
}

void rotate(Splay *x, Splay *&k){
    int d = x->d();
    Splay *p = x->fa;
    p->sc(x->ch[!d], d);
    if(p == k){
        x->fa = k->fa;
        k = x;
    }
    else p->fa->sc(x, p->d());
    x->sc(p, !d);
    p->pup(); x->pup();
}

void splay(Splay *x, Splay *&k){
    for(Splay *y; x != k;){
        if((y = x->fa) != k) y->fa->pdw();
        y->pdw(); x->pdw();
        if(y != k) (x->d() ^ y->d()) ? rotate(x, k) : rotate(y, k);
        rotate(x, k);
    }
}

Splay* select(int k){
    Splay *p = rt;
    while(true){
        p->pdw();
        int t = p->ch[0]->siz;
        if(k <= t) p = p->ch[0];
        else if(k > t + 1){
            k -= t + 1; p = p->ch[1];
        }
        else break;
    }
    return p;
}

void init(){
    char s[N];
    n = read(); m = read();
    scanf("%s", s);
    nil[1].sum = 0, nil[1].siz = 1;
    rt = nil + 1;
    for(int i = 0; i < n; i++){
        nil[2+i].siz = 1;
        nil[2+i].cov((s[i] == '(') ? 1 : -1);
        rt->sc(nil+(2+i), 1);
        splay(nil+(2+i), rt);
    }
    nil[2+n].sum = 0, nil[2+n].siz = 1;
    rt->sc(nil+(2+n), 1);
    splay(nil+(2+n), rt);
}

void work(){
    char s[N];
    Splay *u, *v;
    int x, y;
    while(m--){
        scanf("%s", s);
        x = read(); y = read();
        u = select(x); splay(u, rt);
        u = select(y+2); splay(u, rt->ch[1]);
        v = rt->ch[1]->ch[0];
        switch(s[0]){
            case 'R': scanf("%s", s); v->cov((s[0] == '(') ? 1 : -1); break;
            case 'S': v->rev(); break;
            case 'I': v->flip(); break;
            case 'Q': printf("%d\n", (abs(v->lmn)+1) / 2 + (abs(v->rmx)+1) / 2); break;
        }
    }
}

int main(){
    init();
    work();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章