陣列 線段樹

2022-03-07 06:09:23 字數 2043 閱讀 3095

考慮所有右端點確定為位置$r$的區間,顯然它們的左端點取值可以在某個區間$[l,r]$中

因此我們只需要對每個$r$確定對應的$l$

我們令$pre[i]$表示$i$位置前面第乙個和$i$顏色一樣的位置

那麼$l=max_(pre[i])+1$也就是不能有同時2個出現在區間內

我們列舉$r=1\cdots n$,得到答案表示式:

$ans=\sum_^n r-max(pre[i])=\frac-\sum_^n max(pre[i])$

我們只需要處理後面那個東西

考慮用線段樹維護這個值,令線段樹上區間$[x,y]$表示:$\sum_^ maxn(pre[i])$

我們同時再記錄乙個最大值,表示區間$[x,y]$中$pre[i]$的最大值

線段樹上update的時候,最大值很好維護,但是這個和不太好處理

父親顯然可以直接繼承左兒子的值,而右兒子則不行

因為右兒子記錄的是$\sum_^ maxn(pre[i])$

但是我們需要的是$\sum_^ maxn(pre[i])$

那麼我們可以用左兒子的最大值$val$,帶著它遞迴進入右兒子處理

每次進入右邊的乙個區間,首先判斷當前最大值是否小於等於$val$,如果是,則整個區間一定全部取$val$,直接返回即可

否則判斷當前區間的左兒子是否小於等於$val$,如果是,那麼左邊兒子可以全部取$val$,遞迴進入右邊處理

否則,需要遞迴進入左兒子,注意到此時右兒子中一定全部大於$val$,直接返回即可,不需要再遞迴進入右兒子

(如果上面這段沒有看懂,可以參考**,有注釋)

這樣處理完之後,每次修改的複雜度是$o(\log ^2 n)$,查詢就是輸出線段樹根的值

#include#include#include#include#include#include#define ll long long

using namespace std;

inline ll read()

while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();

return re*flag;

}sets[200010];

ll n,p[200010],a[200010];

namespace seg

void update(ll l,ll r,ll num)

void build(ll l,ll r,ll num)

ll mid=(l+r)>>1;

build(l,mid,num<<1);build(mid+1,r,num<<1|1);

update(l,r,num);

} void change(ll l,ll r,ll num,ll pos,ll val)

ll mid=(l+r)>>1;

if(mid>=pos) change(l,mid,num<<1,pos,val);

else change(mid+1,r,num<<1|1,pos,val);

update(l,r,num); }}

int main()

} seg::build(1,n,1);

ll q=read();

while(q--)

else seg::change(1,n,1,(*suf),0);

}s[a[t1]].erase(it);

s[t2].insert(t1);

it=s[t2].find(t1);

it++;suf=it;it--;

if(suf!=s[t2].end()) seg::change(1,n,1,*suf,t1);

if(it!=s[t2].begin())

else seg::change(1,n,1,t1,0);

a[t1]=t2;

} else printf("%lld\n",(ll)(n*(n+1)/2)-seg::sum[1]);

}}

線段樹(陣列實現)

最近看了很多學長髮的資料,吸取了別人的優點,把query函式更改的更加合理了。我是分割線 線段樹是一棵完美二叉樹,樹上的每個節點都維護乙個區間。根維護的是整個區間,每個節點維護的是父親的區間二等分後的其中乙個子區間。當有n個元素時,對區間的操作可以在o logn 的時間內完成。所以,線段樹是擅長處理...

線段樹,樹狀陣列,主席樹

樹狀陣列 主席樹 包括無修改和可修改。用乙個滿二叉樹 葉子節點可以為空 來維護乙個連續陣列,整個樹的所有葉子節點從左到右表示整個陣列,每個非葉子節點表示其所有葉子的集合所描述的乙個連續子陣列的某一特性 最小值,最大值等 可以在logn的複雜度內實現對任意連續欄位的給定特性的查詢 最小值等 可以在lo...

線段樹 劃分樹 樹狀陣列

線段樹 利用陣列來維護乙個類似字首和的區間和 在查詢的時候查這個區間陣列 特殊操作 有延時標記 在區間陣列上增加基本不改變原來陣列 以達到節省時間的目的 樹狀陣列 和線段樹類似 乙個用乙個陣列維護類似字首和的東西 但 是 它維護的是乙個用二進位制表示的字首和 舉個例子 1是1 2是1 2 3是3 4...