ZJOI2013 K大數查詢

2021-10-08 21:32:19 字數 2065 閱讀 8481

區間求第k小,變為了區間求第k大。

那麼現在,對於插入數的結構體來說,如果q[i].k>mid,就把它劃分到右區間,並進行單點累加;如果q[i].k<=mid,則劃分到左區間。而對於查詢的結構體來說,如果查詢區間內的值,記為sum,當q[i].k>sum時,可知是由於mid不夠小的緣故,所以應該把mid再變小寫,即劃分到左區間;當q[i].k<=sum時,說明mid已經夠大了,所有劃分到右區間。

這裡的劃分,和求第k小相比,好像不是那麼「顯然」與「對稱」了,所以需要注意。

#include

#define int long long

using

namespace std;

const

int n=

5e4+5;

int n,m,q;

int sum[n<<2]

,tag[n<<2]

,ans[n]

;struct nodeq[n<<1]

,q1[n<<1]

,q2[n<<1]

;inline

void

pushdown

(int k,

int l,

int r,

int mid)

}void

change

(int k,

int l,

int r,

int qx,

int qy,

int v)

int mid=l+r>>1;

pushdown

(k,l,r,mid);if

(qx<=mid)

change

(k<<

1,l,mid,qx,qy,v);if

(midchange

(k<<1|

1,mid+

1,r,qx,qy,v)

; sum[k]

=sum[k<<1]

+sum[k<<1|

1];}

intquery

(int k,

int l,

int r,

int qx,

int qy)

void

solve

(int ql,

int qr,

int l,

int r)

int mid=l+r>>1;

int p1=

0,p2=0;

for(

register

int i=ql; i<=qr;

++i)

if(q[i]

.opt==1)

else q1[

++p1]

=q[i];}

else

else

}for

(register

int i=

1; i<=p2;

++i)

if(q2[i]

.opt==1)

change(1

,1,n,q2[i]

.x,q2[i]

.y,-1)

;for

(register

int i=

1; i<=p1;

++i) q[ql+i-1]

=q1[i]

;for

(register

int i=

1; i<=p2;

++i) q[ql+p1-

1+i]

=q2[i]

;solve

(ql,ql+p1-

1,l,mid)

;solve

(ql+p1,qr,mid+

1,r);}

signed

main()

solve(1

,m,-n,n)

;for

(register

int i=

1; i<=q;

++i)

printf

("%d\n"

,ans[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...