題意:給出乙個括號序列,僅包含(和)。三種操作:(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表示翻轉操 作。對於每乙個...