給出乙個01串,每次有兩種操作:
首先,這是一道三倍經驗題。
p2574 xor的藝術
p3870 [tjoi2009]開關
(這兩道題可以用分塊做,但是光開關用分塊會t)
這道題其實就是乙個裸的線段樹。用tre
e[x]
.ltr
ee[x
].l和t
ree[
x].r
tree
[x].
r表示這個區間的左右端點,tre
e[x]
.num
tree
[x].
num表示這個區間有多少個1,tre
e[x]
.laz
ytre
e[x]
.laz
y就是懶惰標記。
其中只有tre
e[x]
.laz
ytre
e[x]
.laz
y和線段樹模板不一樣。由於很明顯如果我們將同乙個區間取反兩次,那麼就是沒有取反的意思。所以,tre
e[x]
.laz
ytre
e[x]
.laz
y其實只要表示這個區間是否被按了奇數次就可以了(按偶數次其實就是按很多個兩次,依舊沒變),所以tre
e[x]
.laz
ytre
e[x]
.laz
y的取值就只會是0或1(0表示按了偶數次,1表示按了奇數次),每次更新時異或1即可。
時間複雜度:o(n
logn
)o(n
logn
)分塊的做法也稍微提一下。可以將這個總區間分成nn
個小區間,每次直接在每個小區間內更新,與分塊模板也很像。
時間複雜度:o(n
n)o(
nn)
線段樹模板:
分塊模板:
#include
#define n 1000100
using
namespace std;
int n,m,w,x,y;
struct node
tree[n*3]
;void
make
(int x)
void
pushdown
(int x)
//下傳標記
}int
ask(
int x,
int l,
int r)
//查詢
void
change
(int x,
int l,
int r)
//修改
if(tree[x]
.l==tree[x]
.r)return
;pushdown
(x);
int mid=
(tree[x]
.l+tree[x]
.r)/2;
if(l>mid)
if(r<=mid)
change
(x*2
,l,mid)
;change
(x*2+1
,mid+
1,r)
; tree[x]
.num=tree[x*2]
.num+tree[x*2+
1].num;
//更新每個區間的值
}int
main()
else
}return0;
}
洛谷3870 開關(線段樹)
題意還是很明顯的,支援區間取反,區間查詢。所以我們線段樹的sum陣列開成二維的,第一維記錄關的燈的數量,第二維記錄開著的燈的數量。push down的lazy標記就swap一下0和1的個數。查詢時返回區間1的sum即可。includeusing namespace std const int max...
洛谷 p3870 開關 線段樹模板
這兩天學了很長時間於是做了一道水題 我就用了模板,就連任何優化都沒有 就ac了,複雜度也很 10個點1500多毫秒 這個題就是把lazy改成記錄下修改的次數,每次修改的時候mod 2,因為反過來再返回去就一樣了 修改變成 sum root r l 1 sum root 其他的幾乎就沒區別了 incl...
線段樹2 洛谷p3373 線段樹
題目位址 解釋 多了乙個乘法操作,可以考慮優先順序。每次先算乘法。首先,對於乙個區間 和為s 假設已經按 a 乘b進行了操作。值得到的值為 s a b sb ab 假設先乘得到 sb a 這樣相比,add應該還要再乘上乙個b才對,所以,當更新到乙個區間時,為了進行先乘的操作而不讓結果發生變化,應該將...