BZOJ K大數查詢(分治)(Zjoi2013)

2022-05-15 17:49:49 字數 1808 閱讀 9485

有n個位置,m個操作。操作有兩種,每次操作如果是1 a b c的形式表示在第a個位置到第b個位置,每個位置加入乙個數c

如果是2 a b c形式,表示詢問從第a個位置到第b個位置,第c大的數是多少。

第一行n,m

接下來m行,每行形如1 a b c或2 a b c

輸出每個詢問的結果

題目大意:略。

思路:分治答案。答案範圍[-n, n],從前往後掃瞄,若是插入操作且c>mid,則把線段樹中區間[a, b]加一,並置為為類別1;否則置為類別0。若是詢問操作,若目前線段樹中區間[a, b]的和小於等於c,則置為類別1;否則置為類別0,並把c減去區間[a, b]的和。然後分治處理,其中類別0中,答案範圍為[-n, mid];類別1中,答案範圍為[mid + 1, n]。按類別排序後,兩個區間之間互不影響。時間複雜度為o(nlognlogn)。

**(4940ms):

1 #include 2 #include 3 #include 4 #include 5

using

namespace

std;

6 typedef long

long

ll;7

8const

int maxn = 50010;9

const

int maxt = maxn << 2;10

11int

sum[maxt];

12int

add[maxt];

13bool

clr[maxt];

1415

#define ll (x << 1)

16#define rr (ll | 1)

17#define mid ((l + r) >> 1)

18void

inittree()

2223

void pushdown(int x, int l, int

r) 29

if(add[x]) 36}

3738

void maintain(int

x) 41

42void modify(int x, int l, int r, int a, int

b) else52}

5354

int query(int x, int l, int r, int a, int

b) else64}

65#undef mid

6667

struct

node

73bool

operator

< (const node &rhs) const

77} p[maxn];

78int

ans[maxn];

79int

n, m;

8081

void work(int a, int b, int l, int

r) 88

inittree();

89int mid = a + ((b - a) >> 1), t = l - 1;90

for(int i = l; i <= r; ++i) else

99 t += !p[i].v;

100}

101 sort(p + l, p + r + 1

);102

work(a, mid, l, t);

103 work(mid + 1, b, t + 1

, r);

104}

105106

intmain()

view code

ZJOI2013 K大數查詢

有n個位置,m個操作。1 a b c形式,表示在第a個位置到第b個位置,每個位置加入乙個數c 2 a b c形式,表示詢問從第a個位置到第b個位置,第c大的數是多少。區間的第k大值有一種二分的做法。二分答案mid,計算出區間內 mid的值有多少個。若數量小於c,則ans mid,否則ans mid。...

ZJOI2013 K大數查詢

有n個位置,m個操作。操作有兩種,每次操作如果是 2 a b c 表示詢問從第a個位置到第b個位置,第c大的數是多少。輸入格式 第一行n,m接下來m行,每行形如1 a b c或2 a b c 輸出格式 輸出每個詢問的結果 solution 整體二分。假設我們現在要解決 ql,qr 並且他們的答案 加...

ZJOI2013 K大數查詢

點此看題 0x01 樹套樹 這道題的思路特別巧妙,樹套樹不一定要用區間線段樹套權值線段樹,還可以反過來套。我們維護乙個動態開點的權值線段樹,每個點代表權值 l,r l,r l,r 在整個區間的出現情況,套上乙個動態開點的區間線段樹,操作1 11對權值線段樹單點修改,然後對每個點的 a,b a,b a...