HNOI2011 括號修復

2022-05-11 00:45:13 字數 3949 閱讀 4217

乙個合法的括號序列是這樣定義的:

空串是合法的。

如果字串 s 是合法的,則(s)也是合法的。

如果字串 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.txt中讀入資料,輸入檔案的第一行是用空格隔開的兩個正整數n和m,分別表示字串的長度和將執行的操作個數。第二行是長度為n的初始字串s。接下來的m行是將依次執行的m個操作,其中操作名與運算元之間以及相鄰運算元之間均用空格隔開。30%的資料滿足

n,m≤3000。100%的資料滿足n,m≤100000。

輸出格式:

輸出檔案 output.txt 包含 t 行,其中 t 是輸入的將執行的 m 個操作中 query 操作出現的次數。query 操作的每次出現依次對應輸出檔案中的一行,該行只有乙個非負整數,表示執行對應 query 操作的結果,即:所指字串至少要改變多少位才能變成合法的括號序列。輸入資料

保證問題有解。

輸入樣例#1:

4 5

((((

replace 1 2 )

query 1 2

swap 2 3

invert 3 4

query 1 4

輸出樣例#1:
1

2

樣例解釋:輸入中有2個query操作,所以輸出有2行。執行第乙個query操作時的括號序列為))((,因改變第1位可使[1,2]之間的字串變成合法的括號序列,故輸出的第一行為1。執行第二個query操作時的括號序列為)((),因要改變第1位和第2位才能使[1,4]之間的字串變成合法的括號序列,故輸出的第二行為2。

終於找到一道不那麼水的模板題了,這道題思維難度還是很高的,一開始看到有翻轉操作就知道是splay,興奮地開始碼**,然後看到取反操作,懵逼?!

這道題如果沒有取反操作就萬事大吉,那麼我們現在假設萬事大吉:

1.直接在splay樹裡面維護兩個數a,b分別表示除去所有配對的括號後左邊還有多少個右括號,右邊還有多少個左括號。

2.瞎幾把維護一下。

3.最後輸出的就是$\frac+\frac$(實際上就是a和b分別除以2然後向上取整)。

最後輸出的答案還是很好理解的,就當把a的一半反過來,把b的一半反過來。

但是...理想是美好的,現實是殘酷的(因為並沒有什麼所謂的萬事大吉)。

那麼怎麼進行取反操作呢?顯然上述的方法是不行的,為什麼呢?

因為上面的方法將已經配對的括號去掉了,然而進過取反操作,這些已經配對好了的括號就有可能會被拆開,從而形成新的未配對的括號。

也就是說上面的方法對於反轉操作來說是有後效性的。那我們該怎麼辦呢?

我們將所有的「(」設為1,將所有的「)」設為-1,那麼對於一對匹配的括號,他們的字首和就是0。

很快我們就可以發現上文所說的a實際上就是最小的字首和,上文所說的b實際上就是最大的字尾和,那麼最大字首和和最小字尾和在這道題中有沒有用呢?

在這裡我們令:

1.lmax表示最大字首和

2.lmin表示最小字首和

3.rmax表示最大字尾和

4.rmin表示最小字尾和

我們發現乙個括號序列取反了之後,lmax=-lmin,lmin=-lmax,rmin=-rmax,rmax=-rmin。(不懂的話可以自己列乙個序列試試)

最後輸出的就是$\frac+\frac$ 當然都要取絕對值。

然後這道題還有一些細節:

1.同時置為某數的操作下,我們要把取反的標記清0。而取反的標記下,我們要把置為某數的標記取反。

2.標記下傳的時候,先傳取反,再傳置數。

為什麼這樣是對的呢?

1.假設是先取反再置為某數:

我們經歷了置數的修改,那麼就把取反的標記清0了,這時我們只有置為某數的標記,所以答案是對的

2.假設是先置為某數再取反:我們經歷了取反的修改,此時置的數也取反了。我們先執行取反操作,沒錯吧?然後再執行置數操作,這時由於置數取反了一遍,所以得到的也是對的

1

//never forget why you start

2 #include3 #include4 #include5 #include6 #include7 #include8

#define ll(x) bst[x].child[0]

9#define rr(x) bst[x].child[1]

10#define son(x,t) bst[x].child[t]

11using

namespace

std;

12int n,m,a[100005

],root,cnt;

13char s[100005

];14

struct

bstbst[100005

];19

void push_up(int

root)

27void add_rev(int

root)

34void add_flag(int

root)

47void add_lazy(int root,int

x)57

else61}

62void push_down(int

root)

68if

(bst[root].flag)

73if

(bst[root].lazy)78}

79void build(int &root,int left,int right,int

fa)93

if(left1

,root);

94if(mid1

,right,root);

95push_up(root);96}

97void rotate(int r,int

t)105

void splay(int r,int

goal)

114 fa=bst[r].fa;

115}

116if(goal==0)root=r;

117}

118int find(int root,int

k)125

int split(int l,int

r)132

intmain()

141 len+=2

;142 build(root,1,len,0

);143

for(i=1;i<=m;i++)

154else

if(ch[0]=='s'

)159

else

if(ch[0]=='i'

)164

else

if(ch[0]=='q'

)168

}169

return0;

170 }

HNOI2011 括號修復

設 nd 4 0 多出來的右括號 1 多出來的左括號 2 取反後多出來的右括號 3 取反後多出來的左括號這樣一來 swap swap 0,3 swap 1,2 swap sn 0 sn 1 invert swap 0,2 swap 1,3 val k 1 replace v siz k v 2 1 ...

HNOI2011 括號修復 Splay

題面 bzoj2329 解析要支援區間翻轉,就可以想到splay了 但是要維護什麼資訊才能得到答案呢,將 看作1,看作 1,記字首最大和為 lx 字尾最小和為 rn 那麼 ans left lceil frac right rceil left lceil left frac right right...

HNOI2011 數學作業

hnoi2011 數學作業 小 c 數學成績優異,於是老師給小 c 留了一道非常難的數學作業題 給定正整數 n 和 m 要求計算concatenate 1.n mod m 的值,其中 concatenate 1.n 是將所有正整數 1,2,n順序連線起來得到的數。例如,n 13,concatenat...