ZJOI2013 K大數查詢

2021-10-03 07:48:06 字數 2157 閱讀 7026

顯然可以線段樹套線段樹。但是必須卡常。

所以我採用了整體二分。注意是區間第k大,而不是第k小。然後區間轉化一下即可。

有乙個剪枝的地方,就是如果這個區間已經沒有查詢的操作了,那就不用遞迴了。

ac**:

#pragma gcc optimize("-ofast","-funroll-all-loops")

#include

#define int long long

using namespace std;

const

int n=

5e4+10;

char

*fs,

*ft,buf[

1<<20]

;#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;

inline

intread()

while

(ch>=

'0'&&ch<=

'9')

return x*f;

}struct nodet[n]

,tl[n]

,tr[n]

;int idx,n,m,res[n]

;int sum[n<<2]

,lazy[n<<2]

,rev[n<<2]

;inline

void

push_down

(int p,

int l,

int r)

if(lazy[p])}

void

change

(int p,

int l,

int r,

int ql,

int qr,

int v)

int mid=l+r>>1;

push_down

(p,l,r);if

(qr<=mid)

change

(p<<

1,l,mid,ql,qr,v)

;else

if(ql>mid)

change

(p<<1|

1,mid+

1,r,ql,qr,v)

;else

change

(p<<

1,l,mid,ql,mid,v)

,change

(p<<1|

1,mid+

1,r,mid+

1,qr,v)

; sum[p]

=sum[p<<1]

+sum[p<<1|

1];}

intask

(int p,

int l,

int r,

int ql,

int qr)

void

solve

(int l,

int r,

int x,

int y)

int mid=l+r>>1;

int cl=

0,cr=

0,fl=

0,fr=0;

rev[1]

=1,sum[1]

=lazy[1]

=0;for

(int i=x;i<=y;i++

)else

}for

(int i=

1;i<=cl;i++

) t[x+i-1]

=tl[i]

;for

(int i=

1;i<=cr;i++

) t[x+cl+i-1]

=tr[i];if

(fl)

solve

(l,mid,x,x+cl-1)

;if(fr)

solve

(mid+

1,r,x+cl,y);}

signed

main()

solve(1

,n,1

,m);

for(

int i=

1;i<=idx;i++

)printf

("%lld\n"

,res[i]);

return0;

}

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...