給定乙個長度為 \(n\) 的括號序列,要求支援兩種操作:
將\([l,r]\) 區間內的括號全部翻轉
求出以\(l\)為左端點時,最長的合法括號序列對應的\(r\)
\(1 ≤ n ≤ 10^6 , 1 ≤ m ≤ 2 × 10^5\)
首先根據這個資料範圍,要想到線段樹
當\(s[i]==( \;a[i]=1\)
當\(s[i]==) \;a[i]=-1\)
乙個顯然的想法是建立乙個線段樹,其節點的值為\(a\)陣列的字首和
那麼對於操作\(1\)如何修改是乙個問題,你會發現不好直接進行修改
可以把這個問題轉化為\([1,l-1]\)和\([1,r]\)修改兩次,顯然是等價的
那麼修改\([1,x]\)會使得\([1,x]\)中的元素乘以\(-1\),使得\([x+1,n]\)中的所有元素\(+2pre[x]\)
對於操作2顯然是要找到在\([l,n]\)中找到乙個最大的\(pos\)使得\(pre[pos]==pre[l-1]\)
並且在\([l,pos-1]\)中不存在\(pre[i]
這個問題比較麻煩,解決的方法也比較巧妙
首先找到\([l,n]\)中第乙個小於\(pre[l-1]\)的\(pos\),那麼答案必定在\([l,pos-1]\)中
再找到\([1,pos-1]\)中座標最接近\(pos-1\)且值小於\(pre[l-1]+1\)的位置
如果這個位置大於\(l\)顯然就是答案,否則為\(0\)
如何尋找\(pos\)就是線段樹上二分,需要維護區間的最大最小值
這個題目要關注的是有兩個\(lazy\)相互影響要注意寫法
#include#define fi first
#define se second
#define debug cout<<"i am here"// 邊界處理
if(l<=l&&r<=r)else if(op==2)
return ;
}updown(node);
int mid=(l+r)/2;
if(mid>=l) update(node<<1,l,r,l,mid,add,op);
if(mid=pos) now=query(node<<1,l,mid,pos);
if(mid=pos&&mi[node<<1]l)else}}
return 0;
}
線段樹yy(線段樹維護括號序列 LCA)
沒有題目鏈結 一顆有 n 個節點的樹,q 組詢問,支援兩種操作 1.單點修改 2.路徑求和。1 n,q 1e5 題解 那麼可以建立一顆有根樹,每次更新時為兩個單點更新 加一次減一次 每次查詢時則是查詢 根的左括號到 x 點的左括號之和 根的左括號到 y 點的左括號之和 2 根的左括號到 x 與 y ...
藍橋杯 操作格仔 線段樹
題目 有n個格仔,從左到右放成一排,編號為1 n。共有m次操作,有3種操作型別 1.修改乙個格仔的權值,2.求連續一段格仔權值和,3.求連續一段格仔的最大值。對於每個2 3操作輸出你所求出的結果。輸入格式 第一行2個整數n,m。接下來一行n個整數表示n個格仔的初始權值。接下來m行,每行3個整數p,x...
藍橋杯 操作格仔 線段樹
剛學習了線段樹,解決區間問題確實是不錯的利器,線段樹實際上就是一棵平衡二叉樹,對於任何操作都能在o long2n 的時間內完成,相比對普通陣列o n 的時間複雜度,有不錯的效率,下面以藍橋網上乙個題操練一下吧。問題描述 有n個格仔,從左到右放成一排,編號為1 n。共有m次操作,有3種操作型別 1.修...