習題 列隊(主席樹)

2022-07-22 06:54:09 字數 1341 閱讀 7180

傳送門考慮如果有一群人直往右跑,那麼設$aim_i \(為最優策略下其的終止位置,設\)p_i\(為他們現在的位置,按照題目給定的式子,消耗的體力值總和即為\)\sum_^|aim_i-p_i|$

因為對於所有的人都有\(aim_i>p_i\),所以原式即為\(\sum_^aim_i-\sum_^p_i\),也就是指他們的互相的位置其實對答案沒有什麼影響,貪心地去考慮,一定有乙個分界點,其左邊的所有人向右跑且不會超過分界點,右邊的所有人向左跑,且不會超過分界點。那麼考慮一顆主席樹,方便裂出\(l\sim r\)中的所有點,這裡的主席樹是按照權值來的,所以可以在主席樹上進行二分,把求出分界點的時間從\(log_nlog_n\)變成\(log_n\),值域範圍需要開兩倍

#pragma gcc optimize(2)

#include#includeusing namespace std;

#define pii pair#define x first

#define y second

namespace io

while('0'<=c&&c<='9')

x*=f;

}void write(long long x)

}namespace lst

int cnt;

struct node

tre[1000000*30+5];

void build(int l,int r,int &k)

void change(int las,int &now,int val,int pos)

change(tre[las].lson,tre[now].lson,val,pos);

change(tre[las].rson,tre[now].rson,val,pos);

tre[now].siz=tre[tre[now].lson].siz+tre[tre[now].rson].siz;

tre[now].val=tre[tre[now].lson].val+tre[tre[now].rson].val;

}pii ask(int las,int now,int l,int r)

long long calc(int las,int now,int k,int add,int dis)

}using namespace lst;

using namespace io;

int n,m;

int rt[500005];

int l,r,k;

long long s[2000005];

int main()

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

return 0;

}

BZOJ5319 軍訓列隊(主席樹)

bzoj 洛谷一眼題既視感。首先很明顯,每次詢問的結果顯然是做一次離散。然後直接上主席樹就好了。查詢答案的方式也很簡單 考慮一下那個絕對值是個什麼東西 如果所有的點都在目標區間以左 則直接區間和去算一下。如果所有的點都在目標區間以右 好像和在左邊一樣的。否則,把區間隔開計算就好了。include i...

洛谷P4559 JSOI2018 列隊(主席樹)

傳送門 首先考慮乙個貪心,我們把所有的人按 a i 排個序,那麼排序後的第乙個人到 k 第二個人到 k 1 第 i 個人到 k i 1 易證這樣一定是最優的 然後發現這裡有乙個很重要的性質,a i 互不相同。那麼就必定存在乙個點 mid 在 mid 左邊 包括 mid 的空格子和人一樣多,右邊 不包...

主席樹 初學

現在才開始學主席樹 弱 不過不帶修改的話 還是很簡單的嘛。或者說應該叫可持久化線段樹?首先對數的區間進行離散化,這樣下面的a i 都預設為離散化以後的結果了。對於每個1.i開乙個線段樹,對於這個線段樹中的每乙個節點 l,r 表示1.i中在 l,r 中的數的個數。顯然這n個線段樹的形態大小是完全一樣的...