慢慢變小的序列(線段樹)

2021-10-24 20:09:39 字數 2316 閱讀 5417

給乙個長度為n

nn的序列a1,

a2,…

an

a_1,a_2,\dots a_n

a1​,a2

​,…a

n​,你需要支援以下兩種操作:

操作1:l r x y,對所有的l≤n

≤r

l \leq n \leq r

l≤n≤

r賦值ai=

min(

ai,(

i−l)

∗y+x

)a_i = min(a_i, (i - l) * y + x)

ai​=mi

n(ai

​,(i

−l)∗

y+x)

。其中l,r,x,y均為整數,且有 1≤l

≤r≤n

1\leq l \leq r\leq n

1≤l≤r≤

n,∣x∣≤

100000

\left| x\right|\leq 100000

∣x∣≤10

0000

,∣ y∣

≤5

\left| y\right|\le 5

∣y∣≤5。

操作 2:x

xx,詢問a

xa_x

ax​ 的值,這裡 x

xx 是整數,且有1≤x

≤n

1\le x\le n

1≤x≤n。

1 ≤n

,q≤1

05

1 \leq n,q \leq 10^5

1≤n,q≤

105−10

5≤ai

≤105

-10^5 \leq a_i \leq 10^5

−105≤a

i​≤1

05首先觀察a

ia_i

ai​的表示式(i−

l)∗y

+x

(i - l) * y + x

(i−l)∗

y+x,我們可以對其進行化簡,即:i∗y

+(x−

l∗y)

i * y + (x - l * y)

i∗y+(x

−l∗y

)。我們觀察到y

yy的取值範圍特別小,於是我們就可以開11

1111

個線段樹去維護,每乙個線段樹代表乙個y

yy,這樣表示式中的y

yy就固定了。因為i∗y

i*yi∗

y是定值,因此我們可以放到最後直接加上,那麼原問題就等價於處理x−l

∗y

x - l * y

x−l∗

y in

,laz

ymin,lazy

min,la

zy,這裡的laz

ylazy

lazy

指的是修改後的最小值標記。

在查詢答案的過程中,遍歷每乙個線段樹,找到其中的最小值再加上i∗y

i*yi∗

y,最後再與a

ia_i

ai​找乙個最小值,就是最終的答案了。

#include

#include

#include

#include

using

namespace std;

const

int n =

100010

, inf =

0x3f3f3f3f

;int n, q;

int w[n]

;struct node

tr[n *4]

[11];

void

pushup

(int k,

int u)

void

pushdown

(int k,

int u)

}void

build

(int k,

int u,

int l,

int r);if

(l==r)

return

;else

}void

modify

(int k,

int u,

int l,

int r,

int x)

else

}int

query

(int k,

int u,

int x)

intmain()

else

}return0;

}

序列 線段樹

使用線段樹維護 b bb,初值為 bi b i bi 每次修改時,若乙個位置上的值變為了 0 00,則說明其會對答案產生新的貢獻,在外部使用樹狀陣列將貢獻計入答案,然後將該位置的值 重置為 bi b i bi 重置的時間複雜度是 o log n o log n o logn 考慮最壞情況,每次操作 ...

序列操作(線段樹)

lxhgww 最近收到了乙個 01 序列,序列裡面包含了 n 1 n 105 個數,這些書要麼是 0,要麼是 1,現在對這個序列有五種變換操作和詢問操作 0 a b 把 a,b 區間內所有數全部變成 0。1 a b 把 a,b 區間內所有數全部變成 1。2 a b 把 a,b 區間內所有數全部取反,...

序列操作 線段樹

題目大意 你要維護乙個長度為n的序列,進行操作。對於這個序列,233之類的數不能出現,也就是說233,2333,23333,233333 這一系列的數不能在序列中出現。1 i 輸出第i個元素。2 a b x 將 a,b 區間的序列賦值為x。3 a b x 將 a,b 區間的序列加上x。4 a b 將...