time limit: 20 sec
memory limit: 259 mb
submit: 894
solved: 423 [
submit][
status]
輸入資料的第一行包含兩個整數n和q,分別表示括號序列的長度,以及操作的個數。 第二行包含乙個長度為n的括號序列。 接下來q行,每行三個整數t、x和y,分別表示操作的型別、操作的開始位置和操作的結束位置,輸入資料保證x不小於y。其中t=0表示詢問操作、t=1表示反轉操作、t=2表示翻轉操作。
對於每乙個詢問操作,輸出一行,表示將括號序列的該子串行修改為配對,所需的最少改動個數。
6 3
)(())(
0 1 6
0 1 4
0 3 4 22
0100%的資料滿足n,q不超過10^5。
思路:對於一段括號匹配結束之後肯定會成為))))((((,或者只剩一種情況,如果最後剩下的未匹配的左括號有x個,右括號有y個,那麼答案就是ans=(x+1)/2+(y+1)/2,也就是將右括號的前半部分變成左括號,左括號的後半部分變成右括號,當兩者是奇數時都需要修改。
所以伸展樹維護四個值,la表示左邊連續最小值(也就是從左邊連續匹配剩下的有括號的數量),lb表示左邊連續最大值,ra,rb類似
那麼答案就是ans=(abs(la)+1)/2+(rb+1)/2=(-la+1)/2+(rb+1)/2;
注意,這兩種形式看起來是等價的,但是後一種才是真正正確的,即包含了所有情況。因為在這裡我們會覺得在大多數時候lmin是個負數。但是有時候可能是正的,比如剩餘括號序列為((((,此時la=1,rb=4,答案為2,即將後兩個修改為右括號。
#include#include#include#include#include#includeusing namespace std;
#define key_value ch[ch[root][1]][0]
const int maxn=100010;
int ch[maxn][2],pre[maxn],rev[maxn],over[maxn],size[maxn],key[maxn];
int la[maxn],lb[maxn],sum[maxn],ra[maxn],rb[maxn];
int root,tot1;
int n,m;
char str[maxn];
void newnode(int &r,int f,int val)
void pushup(int r)
void update_rev(int r)
void update_over(int r)
void pushdown(int r)
if(over[r])
}void build(int &x,int l,int r,int f)
void init()
void rotate(int x,int kind)
void splay(int r,int goal)
else
else}}
pushup(r);
if(goal==0)root=r;
}int get_kth(int r,int k)
void debug(int r)
void reverse(int l,int r)
void over(int l,int r)
void query(int l,int r)
int main()
{ while(scanf("%d%d",&n,&m)!=eof)
{scanf("%s",str);
init();
int op,l,r;
while(m--)
{scanf("%d%d%d",&op,&l,&r);
//cout<
BZOJ2329 括號修復(Splay)
bzoj 洛谷本來想著用線段樹來寫 但是有乙個區間翻轉 所以不能用線段樹了,就只能用平衡樹 然後直接sp lay 就好了 注意一下幾個標記的下放問題 這種資料結構真的沒有什麼思路可言。include include include include include include include in...
BZOJ 2209 括號序列(splay)
題意 給出乙個括號序列,僅包含 和 三種操作 1 將 l,r 區間內的括號反轉,即 變為 變為 2 將 l,r 區間內的括號翻轉,之前為a l a l 1 a r 1 a r 現在為a r a r 1 a l 1 a l 3 詢問 l,r 內至少需要修改多少個括號才能使得兩兩匹配?這裡貌似可以認為這...
BZOJ2329 括號修復(Splay)
bzoj 洛谷本來想著用線段樹來寫 但是有乙個區間翻轉 所以不能用線段樹了,就只能用平衡樹 然後直接 splay 就好了 注意一下幾個標記的下放問題 這種資料結構真的沒有什麼思路可言。include include include include include include include in...