求餘區間的求和類問題 離線 線段樹 HDU4228

2022-05-01 20:06:09 字數 1864 閱讀 2674

題目大意:給乙個陣列a,他的順序是嚴格的單調增,然後有如下三個操作

①加入乙個val到a陣列裡面去,加入的位置就是a[i-1]②刪除乙個a[i]=val的值

③查詢所有下標i%5=3的值

思路:線段樹+離線

首先因為線段樹中不支援新增、刪除操作的,所以只能離線把所有的val離散化以後放到區間裡面去。然後關鍵就是線段樹是怎麼建立的。

我們知道,每個%5都會有0,1,2,3,4這5個值,然後我們可以通過線段樹來維護這5個值。我們首先用sum[5]表示能被5整除的5種求餘後不同型別的數的val,然後再用cnt記錄當前這個區間裡面還存在的數值。接下來我們定義父親區間,左子區間和右子區間,然後我們發現左子區間的區間範圍和父親區間的是一樣的,然後右子區間的範圍要發生改變,他的位置改變到如下位置:(i+cnt)%5,其中i表示右子區間的第幾個區間,然後cnt表示左子區間的有效的個數。然後我們就這樣去維護就好啦。

//

看看會不會爆int!陣列會不會少了一維!

//取物問題一定要小心先手勝利的條件

#include using

namespace

std;

#define ll long long

#define all(a) a.begin(), a.end()

#define pb push_back

#define mk make_pair

#define fi first

#define se second

const

int maxn = 1e5 + 5

;struct

point

}tree[maxn

<< 2

];ll a[maxn];

intq;

pair

ch[maxn];

void buildtree(int o, int l, int

r)

int mid = (l + r) / 2

;

if (l <= mid) buildtree(o << 1

, l, mid);

if (r > mid) buildtree(o << 1 | 1, mid + 1

, r);

tree[o].init();

}inline

void push_up(int

o)void display(int o, int l, int

r)void update(int o, int l, int r, int pos, bool

flag)

else

return

; }

int mid = (l + r) / 2

;

if (pos <= mid) update(o << 1

, l, mid, pos, flag);

if (pos > mid) update(o << 1 | 1, mid + 1

, r, pos, flag);

memset(tree[o].sum,

0, sizeof

(tree[o].sum));

for (int i = 0; i < 5; i++)

///display(o, l, r);

push_up(o);

return;}

intmain()

sort(a + 1, a + 1 + n);///

有待商榷

buildtree(1, 1

, n);

for (int i = 1; i <= q; i++)

else}}

return0;

}

view code

線段樹 的單點更新和區間求和

include int sum 100 void build int lift,int right,int rt void updata int point,int add,int lift,int right,int rt int query int l,int r,int l,int r,int...

POJ2823 線段樹求區間的最值

本來想搞單調佇列的.結果網上搜單調隊你列的題.一搜搜到這道.一看.果斷敲線段樹.還沒寫過線段樹求最值的.在求和上稍微修改下就可以了.而且這個題目沒有修改的.所以一開始建好樹後.不需要updata.只要尋找答案就可以了.這個程式的主心部分就是如何用線段樹求最值.首先來看初始化的問題.既然我們要求一段區...

求n個閉區間的所有交集(貪心 線段樹)

問題描述 給你n個閉區間,輸出這n個開區間的所有交區間,可能存在乙個子區間有多次重複,乙個交區間的定義是至少有兩個大區間都包含它,並且答案集中要盡可能地把所有區間合併。注 為了避免歧義,頭對尾交於乙個點則不算交。思路 這是對於力扣986地乙個拓展,如果問題約束到乙個交區間最多只有兩個大區間包含它,那...