點此看題
0x01 樹套樹
這道題的思路特別巧妙,樹套樹不一定要用區間線段樹套權值線段樹,還可以反過來套。
我們維護乙個動態開點的權值線段樹,每個點代表權值[l,
r]
[l,r]
[l,r
]在整個區間的出現情況,套上乙個動態開點的區間線段樹,操作1
11對權值線段樹單點修改,然後對每個點的[a,
b]
[a,b]
[a,b
]區間修改。
操作2
22先算右子樹根的[a,
b]
[a,b]
[a,b
]和,如果答案在裡面,找右子樹,否則減掉之後找左子樹,最後跑到葉子就得到了答案,時間複雜度o(n
log2)
o(n\log^2)
o(nlog2)
,空間複雜度o(n
log2)
o(n\log^2)
o(nlog2)
。這道題是需要卡常的,sum
sumsu
m需要開uns
igne
d_in
tunsigned\_int
unsign
ed_i
nt,輸入的c
cc要開lon
g_lo
ng
long\_long
long_l
ong。
#include
#define uint unsigned int
#define ll long long
const
int maxn =
500005
;int
read()
int n,m,a,b,rt,cnt1,cnt2;ll c;
struct node1
tr[maxn*40]
;struct node2
tr[maxn*20]
;void
modify
(int x,
int l,
int r,
int v)
voidup(
int x)
void
down
(int x,
int l,
int r)
void
add(
int&x,
int l,
int r,
int l,
int r)
down
(x,l,r)
;int mid=
(l+r)
>>1;
add(tr[x]
.ls,l,mid,l,r)
;add
(tr[x]
.rs,mid+
1,r,l,r);up
(x);
}uint query
(int x,
int l,
int r,
int l,
int r)
void
modify
(int
&x,int l,
int r,
int id)
intquery
(int
&x,int l,
int r,
int s)
intmain()
if(op==2)
}}
0x02 整體二分
首先我們把詢問和修改放在一起,然後在遞迴的時候維護(ql
,qr,
l,r)
(ql,qr,l,r)
(ql,qr
,l,r
),就表示[ql
,qr]
[ql,qr]
[ql,qr
]之間詢問的答案在[l,
r]
[l,r]
[l,r
]之中,每次拆分的時候考慮權值的中點mid
midmi
d,然後維護出乙個樹狀陣列(這裡的區間修改為加1
11,可以同時支援區間修改和區間查詢),修改的話考慮是否大於mid
midmi
d,如果大於mid
midmi
d就把這個修改歸類到右邊,同時修改樹狀陣列,否則歸類到左邊,不修改。
詢問的話就先算出這個區間中大於mid
midmi
d的個數,如果大於mid
midmi
d就分到左邊(因為答案在左邊,參考線段樹這類問題的求法),然後減去這個個數,否則分到右邊。最後我們把左右分別遞迴,知道權值區間只剩乙個值就確定了答案。
#include
#define int long long
const
int m =
50005
;int
read()
int n,m,c1[m]
,c2[m]
,pd[m]
,ans[m]
;struct node
p[m]
,l[m]
,r[m]
;int
lowbit
(int x)
void
upd(
int x,
int f)
intask
(int x)
void
cdq(
int ql,
int qr,
int l,
int r)
int mid=
(l+r)
>>
1,nl=
0,nr=0;
for(
int i=ql;i<=qr;i++
)else
}for
(int i=ql;i<=qr;i++)if
(p[i]
.op==
1&& p[i]
.v>mid)
upd(p[i]
.l,-1)
,upd
(p[i]
.r+1,1
);for(
int i=
1;i<=nl;i++
) p[ql+i-1]
=l[i]
;for
(int i=
1;i<=nr;i++
) p[ql+nl+i-1]
=r[i]
;cdq
(ql,ql+nl-
1,l,mid)
;cdq
(ql+nl,qr,mid+
1,r);}
signed
main()
;if(op==
2) pd[i]=1
;}cdq(
1,m,
1,n)
;for
(int i=
1;i<=m;i++)if
(pd[i]
)printf
("%d\n"
,ans[i]);
}
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大數查詢
顯然可以線段樹套線段樹。但是必須卡常。所以我採用了整體二分。注意是區間第k大,而不是第k小。然後區間轉化一下即可。有乙個剪枝的地方,就是如果這個區間已經沒有查詢的操作了,那就不用遞迴了。ac pragma gcc optimize ofast funroll all loops include de...