線段樹維護區間01

2022-06-08 16:33:08 字數 4566 閱讀 4639

g. 小 w 開關燈 [ problem 4467

] [ discussion ]

description

晚上到家小 w 通過開關燈來保持自己神經的興奮以便清醒地理筆記。n

'>n(2≤

n≤100,

000'>2≤n≤100,000

)盞燈被連續的編號為 1…n

'>1…n

。剛回到家的時候,所有的燈都是關閉的。 

小w 通過 n

'>

n個按鈕來控制燈的開關, 按第 i

'>i

個按鈕可以改變第 i

'>i

盞燈的狀態。 

小w 發出 m

'>m(1≤

m≤100,

000'>1≤m≤100,000

)條指令,每個指令都是兩個整數中的乙個(0 或 1)。 

第1 種指令(用 0 表示)包含兩個數字 s

i'>si

si 和 e

i'>ei(1≤

si≤e

i≤n'>1≤si≤ei≤n

),它們表示起始開關和終止開關。小 w 需要把從 s

i'>si

到 ei

'>ei

之間的按鈕都按一次,就可以完成這個指令。 

第2 種指令(用 1 表示)同樣包含兩個數字 s

i'>si

和 ei

'>ei(1≤

si≤e

i≤n'>1≤si≤ei≤n

),不過這種指令是詢問從 s

i'>si

到 ei

'>ei

之間的燈有多少是亮著的。 

請你幫助小 w 得到正確的答案。 

input

第1 行: 用空格隔開的兩個整數 n

'>

n 和 m

'>

m。 第2..m+1

'>m+1

行: 每行表示乙個操作, 有三個用空格分開的整數: 指令號, s

i'>si

和 ei

'>ei

。 output

對於每一次詢問, 輸出一行表示詢問的結果。

samples

input copy

4 5

0 1 2

0 2 4

1 2 3

0 2 4

1 1 4

output

1

2

hint

【樣例解釋】

一共有 4 盞燈, 5 個指令。 下面是執行的情況:

1 2 3 4

init: o o o o o = 關 * = 開

0 1 2 -> * * o o 改變燈 1 和 2 的狀態

0 2 4 -> * o * *

1 2 3 -> 1 輸出在 2..3 的範圍內有多少燈是亮的

0 2 4 -> * * o o 改變燈 2 ,3 和 4 的狀態

1 1 4 -> 2 輸出在 1..4 的範圍內有多少燈是亮的

【資料規模】

source

石光中學 2018泉州集訓提高組day4

這個題一看就是要用線段樹做

主要是要知道乙個知識 t[p].s=t[p].r-t[p].l+1-t[p].s;(就是區間長度為5,有兩個2,t[p].s=2,如果反轉的話,t[p].s=5-2=3)

這個就是區間變化之後怎麼區間和

然後在弄乙個區間懶惰標記判斷要不要下傳標記,就是區間是不是要變換

#pragma gcc optimize(1)

#pragma gcc optimize(2)

#pragma gcc optimize(3,"ofast","inline")#include

using

namespace

std;

typedef

long

long

ll;template

void read(tp &x)

if(ch=='-'

)else fh=1

;

while(ch>='

0'&&ch<='9'

) x*=fh;

}inline

char

read1()

const

int maxn=5e6+100

; struct

nodet[maxn];

void build(int p,int l,int

r)

int mid=(l+r)/2

; build(

2*p,l,mid);

build(

2*p+1,mid+1

,r);

} void push(int

p) }

void update(int p,int l,int

r)

if(t[p].lazy) push(p);

int mid=(t[p].l+t[p].r)/2

;

if(l<=mid)

if(r>mid)

t[p].s=t[2*p].s+t[2*p+1

].s;

} int query(int p,int l,int

r)

int ans=0

;

if(t[p].lazy) push(p);

int mid=(t[p].l+t[p].r)/2

;

if(l<=mid)

if(r>mid)

return

ans;

}int

n,m;

intmain()

else

if(op==1

) }

}

一開始wa了好幾遍是這樣寫的,就是沒有異或1,而是變化一次就把他變成一

void push(int

p) }

void update(int p,int l,int

r)

這樣有乙個問題,就是

就是1-2區間變化兩次,而這個區間是一整個節點沒有在update中下傳標記,在詢問中下傳標記時下傳了一次,

本來該沒有變化的,就是如果用異或的話詢問兩次的話,就變成0了,就不會出現上面的情況了

#pragma gcc optimize(1)

#pragma gcc optimize(2)

#pragma gcc optimize(3,"ofast","inline")#include

using

namespace

std;

typedef

long

long

ll;template

void read(tp &x)

if(ch=='-'

)else fh=1

;

while(ch>='

0'&&ch<='9'

) x*=fh;

}inline

char

read1()

const

int maxn=5e6+100

; struct

nodet[maxn];

void build(int p,int l,int

r)

int mid=(l+r)/2

; build(

2*p,l,mid);

build(

2*p+1,mid+1

,r);

} void push(int

p) }

void update(int p,int l,int

r)

if(t[p].lazy) push(p);

int mid=(t[p].l+t[p].r)/2

;

if(l<=mid)

if(r>mid)

t[p].s=t[2*p].s+t[2*p+1

].s;

} int query(int p,int l,int

r)

int ans=0

;

if(t[p].lazy) push(p);

int mid=(t[p].l+t[p].r)/2

;

if(l<=mid)

if(r>mid)

return

ans;

}int

n,m;

intmain()

else

if(op==1

) }

}

維護序列(線段樹維護區間乘 區間加)

給定乙個長度為n的原序列和模數mod,m個操作,a,b 區間乘c,a,b 區間加c,統計 a,b 的區間和。思路 線段樹維護的還是區間和,但是這裡我們需要用到兩個懶標記,乙個記錄加法,乙個記錄乘法,乘法懶標記下傳之後要重置為1而不是0。對於乙個乘法操作,他影響的是區間和還有這個區間的加法標記 乘法標...

線段樹 離散區間,單點維護區間

這道題當時用線段樹搞不行,用主席樹搞,也不行。當場自閉。其實當時想到離散,但是沒想到用單點維護線段樹的區間。你這樣想,無非就是2e6次詢問,最多1 e9被分成最多2e6區間,我們要求的位置,一定在這2e6點的右邊第乙個。那麼把這個點,以及這個點x以及x 1的點儲存下來。維護的時候,線段樹初始化所有的...

線段樹 離散區間,單點維護區間

這道題當時用線段樹搞不行,用主席樹搞,也不行。當場自閉。其實當時想到離散,但是沒想到用單點維護線段樹的區間。你這樣想,無非就是2e6次詢問,最多1 e9被分成最多2e6區間,我們要求的位置,一定在這2e6點的右邊第乙個。那麼把這個點,以及這個點x以及x 1的點儲存下來。維護的時候,線段樹初始化所有的...