在?看看整體二分
整體二分是個啥,就是遞迴進行二分答案的操作,按照當前二分出的區間對詢問操作和修改操作進行左右分類。有點類似於歸併排序的樣子,但是需要用個維護區間的資料結構來維護當前詢問區間的區間的查詢和修改操作,每次查詢完當前區間的操作之後,需要清空之前的修改操作。整體二分可以保證會互相影響的操作可以按照順序進行。但是本質還是離線演算法。
這樣執行的操作時間複雜度是o(m
∗log
(ans
)∗lo
g(m)
)o(m*log(ans)*log(m))
o(m∗lo
g(an
s)∗l
og(m
))poj2104 查詢區間第k小
需要乙個樹狀陣列來維護區間元素個數。
#include
#include
#include
#define ll long long
#define inf 1999122700ll
using
namespace std;
const
int maxn=
200000
;int
lowbit
(int x)
int n,m,cnt;
int tr[maxn+4]
;void
add(
int x,
int v)
intquery
(int x)
struct quc
quc(
int _l,
int _r,
int _k,
int _p,
int _t)
}pl[maxn+4]
,pl[maxn+4]
,pr[maxn+4]
;int ans[maxn+4]
;void
solve
(ll l,ll r,
int l,
int r)
return;}
ll mid=
(l+r)
>>1;
int cl=
0,cr=0;
for(
int i=l;i<=r;i++
)else
}else
else}}
for(
int i=
1;i<=cl;i++)}
for(
int i=
1;i<=cl;i++
)pl[l-
1+i]
=pl[i]
;for
(int i=
1;i<=cr;i++
)pl[l-
1+cl+i]
=pr[i]
;solve
(l,mid,l,l+cl-1)
;solve
(mid+
1,r,l+cl,r);}
intw33ha()
for(
int i=
1;i<=m;i++
)solve
(-inf,inf,
1,cnt)
;for
(int i=
1;i<=m;i++
)printf
("%d\n"
,ans[i]);
return0;
}int
main()
bzoj3110
有n
nn個格仔,開始每個格仔都是空的。
有m
mm個操作。
兩種操作,乙個查詢區間所有元素的第k
kk大,第二個操作是區間的格仔內新增數字。
插入的數字c可以變為inf
−c+1
inf-c+1
inf−c+
1,這樣查詢的時候就會變成查詢第k
kk小了,然後記答案的時候記成inf
−l+1
inf-l+1
inf−l+
1即可第二個操作可以變為區間加。那麼用線段樹代替樹狀陣列即可。
#include
#define ll long long
#define inf (1ll<<31)-1
using
namespace std;
const
int maxn=
50000
;int n,m;
struct treetr[
500004];
struct quc
quc(
int _l,
int _r,ll _k,
int _p,
int _t)
}pl[
(maxn<<1)
+4],pl[
(maxn<<1)
+4],pr[
(maxn<<1)
+4];
int cnt;
ll ans[
(maxn<<1)
+4];
void
pushdown
(int k,
int l,
int r)
void
add(
int k,
int l,
int r,
int a,
int b,
int v)
pushdown
(k,l,r)
;int mid=
(l+r)
>>1;
if(b<=mid)
add(k<<
1,l,mid,a,b,v)
;else
if(a>mid)
add(k<<1|
1,mid+
1,r,a,b,v)
;else
tr[k]
.w=tr[k<<1]
.w+tr[k<<1|
1].w;}
ll query
(int k,
int l,
int r,
int a,
int b)
pushdown
(k,l,r)
;int mid=
(l+r)
>>1;
if(b<=mid)
return
query
(k<<
1,l,mid,a,b)
;else
if(a>mid)
return
query
(k<<1|
1,mid+
1,r,a,b)
;else
}void
solve
(ll l,ll r,
int l,
int r)
return;}
ll mid=
(l+r)
>>1;
int cl=
0,cr=0;
for(
int i=l;i<=r;i++
)else
}else
else}}
for(
int i=
1;i<=cl;i++
)for
(int i=
1;i<=cl;i++
)pl[l-
1+i]
=pl[i]
;for
(int i=
1;i<=cr;i++
)pl[l-
1+cl+i]
=pr[i]
;solve
(l,mid,l,l+cl-1)
;solve
(mid+
1,r,l+cl,r);}
intmain()
solve
(-inf,inf,
1,m)
;for
(int i=
1;i<=cnt;i++
)printf
("%lld\n"
,ans[i]);
return0;
}
整體二分 學習筆記
作者會把自己學習時遇到的一些疑問回答,盡量寫的詳細 合理,讓更多人能夠理解這個演算法。顧名思義,整體二分是處理這樣一種問題 可以使用二分法解決,但是對於每乙個詢問都進行一次二分時間複雜度無法接受的問題。這時候,整體二分就誕生了 它先將所有操作讀入,然後進行乙個統一的二分,或者說 分治。因為是一次性處...
演算法學習 整體二分
我們開門見山,講講一道sb題 給你乙個陣列,查這個陣列的第x大元素。排序?可以 二分?怎麼做啊?二分出乙個mid,判斷這個陣列中有多少個數小於等於mid,如果個數大於等於x,就遞迴到 l,mid 區間,否則是 mid 1,r 區間,這樣遞迴下去就能得到結果。怎麼計算小於等於mid的個數?for一遍原...
整體二分專題
何謂整體二分?一般的二分只適用於單個詢問的,如果有很多個詢問,就變成了n 2n 2 n2或更高但整體二分則可以迅速處理多個詢問的問題 首先需要離線,讀入所有詢問 然後我們二分答案,這時候我們將詢問分成兩個部分,如果l r就直接更新答案,否則考慮分治,詢問的答案在左邊的丟到左邊,答案在右邊的則丟到右邊...