BZOJ 2209 括號序列(splay)

2021-09-07 23:10:50 字數 1548 閱讀 5121

題意:給出乙個括號序列,僅包含(和)。三種操作:(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]內至少需要修改多少個括號才能使得兩兩匹配?這裡貌似可以認為這個詢問的區間長度為偶數。

思路:對於一段括號,最後未匹配的必然是))))((((這種形式,或者是只剩下一種括號。假如現在知道最後未匹配的右括號為x個,左括號為y個,那麼最少修改個數為:

即可以將右括號的前一半修改為左括號,左括號的後一半修改為右括號;若x和y為奇數,則各剩下乙個,這兩個剩下的均需要修改。為了比較容易維護,我們將左括號看做1,右括號看做-1,splay的每個節點儲存lmin(左端連續最小和),lmax,rmin,rmax,這樣剩餘的右括號的個數顯然就是-lmin,剩餘的左括號的個數就是rmax,那麼答案就是:

注意,這兩種形式看起來是等價的,但是後一種才是真正正確的,即包含了所有情況。因為在這裡我們會覺得在大多數時候lmin是個負數。但是有時候可能是正的,比如剩餘括號序列為((((,此時lmin=1,rmax=4,答案為2,即將後兩個修改為右括號。

struct node

void turnover()

};node a[n],*root,*nullnode;

int cnt;

void pushup(node *p)

int ok(node *p)

void pushdown(node *p)

if(p->op2)

}node *newnode(int val,node *p)

void init()

void zig(node *x)

pushup(p);

pushup(x);

if(root==p) root=x;

}void zag(node *x)

pushup(p);

pushup(x);

if(root==p) root=x;

}void splay(node *x,node *goal)

else

}else}}

void select(int k,node *goal)

pushdown(p);

}splay(p,goal);

}node *build(int l,int r,char str,node *p)

void insert(int p,int n,char str)

int query(int l,int r)

void flip(int l,int r)

void turnover(int l,int r)

int n,m;

char str[n];

int main()

}

Splay括號匹配(BZOJ2209)

time limit 20 sec memory limit 259 mb submit 894 solved 423 submit status 輸入資料的第一行包含兩個整數n和q,分別表示括號序列的長度,以及操作的個數。第二行包含乙個長度為n的括號序列。接下來q行,每行三個整數t x和y,分別表...

BZOJ 2209 Jsoi2011 括號序列

輸入資料的第一行包含兩個整數n和q,分別表示括號序列的長度,以及操作的個數。第二行包含乙個長度為n的括號序列。接下來q行,每行三個整數t x和y,分別表示操作的型別 操作的開始位置和操作的結 束位置,輸入資料保證x不小於y。其中t 0表示詢問操作 t 1表示反轉操作 t 2表示翻轉操 作。對於每乙個...

2209 Jsoi2011 括號序列

輸入資料的第一行包含兩個整數n和q,分別表示括號序列的長度,以及操作的個數。第二行包含乙個長度為n的括號序列。接下來q行,每行三個整數t x和y,分別表示操作的型別 操作的開始位置和操作的結 束位置,輸入資料保證x不小於y。其中t 0表示詢問操作 t 1表示反轉操作 t 2表示翻轉操 作。對於每乙個...