乙個合法的括號序列是這樣定義的:
空串是合法的。
如果字串 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輸出樣例#1:((((
replace 1 2 )
query 1 2
swap 2 3
invert 3 4
query 1 4
1樣例解釋:輸入中有2個query操作,所以輸出有2行。執行第乙個query操作時的括號序列為))((,因改變第1位可使[1,2]之間的字串變成合法的括號序列,故輸出的第一行為1。執行第二個query操作時的括號序列為)((),因要改變第1位和第2位才能使[1,4]之間的字串變成合法的括號序列,故輸出的第二行為2。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...