區間求第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...