給出乙個長度為n
n的序列,m
m次詢問,求區間[l,
r][l
,r]
以下內容參考lyd先離散化不解釋。lyd《演算法競賽高階指南》。
分塊演算法一般都是以「暴力+區間預處理+暴力」的方法做的。所以,我們把n
n分成t
t塊,每塊長度⌊tn
⌋⌊nt
⌋。然後預處理出對於任意兩個區間內的數字個數。也就是說,對於任意的1≤l
≤r≤t
1≤l≤
r≤t,我們用cnt
[l][
r][i
]cnt
[l][
r][i
]表示塊l∼r
l∼r內數字i
i的個數。
如何預處理出這一部分?
同時在預處理cnt
cnt的時候順便處理出max
[l][
r]ma
x[l]
[r],表示區間眾數,然後記錄眾數的個數。
接下來就是如何處理答案了。
對於任意一組詢問,設詢問區間[l,
r][l
,r],那麼先記錄q,p
q,p分別表示l,r
l,r所在的塊。如果p−q
≤1p−
q≤1,那麼這兩個塊中間就沒有多餘的整塊,直接樸素求眾數。
否則在cnt
[q+1
][p−
1]cn
t[q+
1][p
−1]的整塊區間中,加上[l,
r[q]
],[l
[p],
r][l
,r[q
]],[
l[p]
,r]之間的數字,然後求出答案。最後再減去加上的數就可以了。
演算法時間複雜度為o(n
t2+m
tn)o
(nt2
+nmt
),空間複雜度為o(n
t2)o
(nt2
)。為了平均時間,不妨設nt2
=mtn
nt2=
nmt
,解得t≈n
3t≈3
n。此時時間複雜度約為o(n
53)o
(n35
)。
#include
#include
#include
#include
using
namespace std;
const
int n=
50010
;int a[n]
,b[n]
,cnt[40]
[40][n]
,l[40
],r[40]
,pos[n]
,sum[n]
,max[40]
[40][
2],be[n]
;int n,m,t,x,y,len,tot,last;
intask
(int l,
int r)
return ans;
} maxn=max[q+1]
[p-1][
0]; ans=max[q+1]
[p-1][
1];for
(int i=l;i<=r[q]
;i++
)for
(int i=l[p]
;i<=r;i++
)for
(int i=l;i<=r[q]
;i++
) cnt[q+1]
[p-1
][a[i]]--
;for
(int i=l[p]
;i<=r;i++
) cnt[q+1]
[p-1
][a[i]]--
;return ans;
}int
main()
sort
(b+1
,b+1
+n);
tot=
unique
(b+1
,b+1
+n)-b-1;
for(
int i=
1;i<=n;i++
) t=
(int
)pow((
double
)n,1.0
/3.0);
len=n/t;
if(t*len;for
(int i=
1;i<=t;i++
) pos[j]
=i;}
}for
(int k=
1;k)for
(int i=
1;i<=t-k;i++)}
}while
(m--
)return0;
}
洛谷P4168 Violet 蒲公英 分塊
時空限制 2000ms 512mb 題目描述 在鄉下的小路旁種著許多蒲公英,而我們的問題正是與這些蒲公英有關。為了簡化起見,我們把所有的蒲公英看成乙個長度為n的序列 a 1,a 2 a n 其中ai為乙個正整數,表示第i棵蒲公英的種類編號。而每次詢問乙個區間 l,r 你需要回答區間裡出現次數最多的是...
蒲公英(洛谷4168分塊)
傳送門 若題目是詢問區間是否有過半眾數,就是主席樹,按值域建樹,不斷判斷左右子樹子節點數量大於 r l 1 2,如果一直可以到葉子節點,則return true,否則return false 若題目是詢問區間是否有過半眾數且帶修改,就是樹套樹 雖然我還沒打過樹套樹 那我們可以考慮分塊做法,n 400...
P4168 Violet 蒲公英 分塊
題目鏈結 分塊。p i j 表示第 i 個塊到第 j 個塊內的眾數,預處理出來就好了,列舉 i 和 j 是 o sqrt n 的,列舉 j 塊內的數也是 o sqrt n 的,總複雜度 o n sqrt n sum i h 表示前 i 個塊數字 h 出現的個數,預處理是 o n 的。對於每乙個查詢,...