題意:給一串括號,有2個操作,1。翻轉某個括號。2。查詢某段區間內化簡後第k個括號是在原序列中的位置。1≤n,q≤200000.
題解:可以知道,化簡後的序列一定是)))((((這種形式的。
線段樹每個節點就存對應區間內化簡後的ls也就是)的數量,rs也就是(的數量。
然後我先把區間[l,r]找出來合併一遍,找出第k個是哪一種擴號。
問題轉化為找區間[l,r]中的第kk個左擴號或者右括號。
我們可以發現,如果是)這種括號,區間從左到右合併的時候是單調不減的。
同理,(這種括號,區間從右往左合併的時候也是單調不減的。
然後我是變成從左往右的第kk個),或者從右往左的第kk個(。
細節挺多的。
1 #include2 #include3 #include4 #include5 #include6using
namespace
std;78
const
int n=200010;9
intn,m,tl,cl,c[n];
10char
s[n];
11struct
nodet[2*n];
1415
int maxx(int x,int y)
1617
node upd(node x,node lc,node rc)
1828
29int bt(int l,int
r)30
43else
4448
return
x;49}50
51void change(int x,int
p)52
54int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)/2;55
if(p<=mid) change(lc,p);
56else
change(rc,p);
57 t[x]=upd(t[x],t[lc],t[rc]);58}
5960
void query(int x,int l,int
r)61
63int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)/2;64
if(r<=mid) query(lc,l,r);
65else
if(l>mid) query(rc,l,r);
66else
6771}72
73int fd(int x,int k,int
tmp)
7482
else
8387}88
89int
main()
90109
else
110116
if(now.ls>=k)
117130 p0=p1;
131}
132}
133}
134else
135145 p0=p1;
146}
147}
148}
149 printf("
%d\n
",ans);
150}
151}
152}
153return0;
154 }
線段樹yy(線段樹維護括號序列 LCA)
沒有題目鏈結 一顆有 n 個節點的樹,q 組詢問,支援兩種操作 1.單點修改 2.路徑求和。1 n,q 1e5 題解 那麼可以建立一顆有根樹,每次更新時為兩個單點更新 加一次減一次 每次查詢時則是查詢 根的左括號到 x 點的左括號之和 根的左括號到 y 點的左括號之和 2 根的左括號到 x 與 y ...
序列 線段樹
使用線段樹維護 b bb,初值為 bi b i bi 每次修改時,若乙個位置上的值變為了 0 00,則說明其會對答案產生新的貢獻,在外部使用樹狀陣列將貢獻計入答案,然後將該位置的值 重置為 bi b i bi 重置的時間複雜度是 o log n o log n o logn 考慮最壞情況,每次操作 ...
藍橋杯 翻轉括號序列 題解 線段樹 思維
給定乙個長度為 n 的括號序列,要求支援兩種操作 將 l,r 區間內的括號全部翻轉 求出以 l 為左端點時,最長的合法括號序列對應的 r 1 n 10 6 1 m 2 10 5 首先根據這個資料範圍,要想到線段樹 當 s i a i 1 當 s i a i 1 乙個顯然的想法是建立乙個線段樹,其節點...