題目大意:給乙個陣列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表示左子區間的有效的個數。然後我們就這樣去維護就好啦。
//view code看看會不會爆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;
}
線段樹 的單點更新和區間求和
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地乙個拓展,如果問題約束到乙個交區間最多只有兩個大區間包含它,那...