顯然可以線段樹套線段樹。但是必須卡常。
所以我採用了整體二分。注意是區間第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...