給定乙個長度為
n n
的序列,並提出
q' role="presentation">q
q個詢問,每次詢問要求回答區間 [l
,r] [l,
r]
內所有的權值與其出現次數的積的最大值。
我一看,區間問題,無修改可以離線,上莫隊妥妥的,但是仔細一想,當區間擴充時,可以o(
1)o (1
)的求出新區間答案,但是當區間縮小時,就不能o(
1)o (1
)做到了,莫隊演算法的複雜度不能得到保證。
這時候就可以考慮回滾莫隊,其思想還是對詢問排序,並且對區間的雙指標有優化。
普通的莫隊演算法,初始的l,
r l,r
就是第乙個詢問的位置的[l
,r] [l,
r]
,之後對l,
r l,r
就沒有人為的修改操作,只讓他隨著詢問變化,在能夠o(
1)o (1
)求出新區間答案的時候,這樣的莫隊演算法保證了複雜度在
n1.5
n
1.5。
此時,由於不能直接o(
1)o (1
)求出區間擴張(或收縮)的時候,需要手動調整這兩個指標的位置,以達到回滾的操作。
第一步,對序列分塊,詢問排序。
第二步,指定ql為當前詢問的l所在塊的下一塊的第乙個元素,指定qr為當前詢問l所在塊的最後乙個元素。對於每乙個詢問,我們要判斷
如果當前詢問的r也在l的塊內,那麼直接暴力統計區間答案,複雜度不超過n−−√n
。如果當前詢問的r不在l的塊內,那麼就讓qr向右拓展,並暫存拓展結果,讓ql向左拓展,然後統計區間
答案。這一步和普通的莫隊沒有區別。
第三步,回滾。我們讓ql回滾到當前l所在塊的下一塊第乙個元素,為下一次詢問做準備。恢復暫存的拓展結果。
對於以上步驟,如果詢問l所在塊與上乙個詢問l所在塊不同,就需要重新指定ql和pr。
由於在乙個塊內的詢問,qr是不回退的,這就保證了複雜度!
如果還是不明白,可以看看下面的部落格。
#include
using
namespace
std;
typedef
double db;
typedef
long
long ll;
typedef
unsigned
long
long ull;
const
int nmax = 1e5+7;
const
int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull mod = 1610612741;
int n,m;
vector
v;ll t;
ll a[nmax],inocc[nmax],glocc[nmax],ans;
int belong[nmax],idx[nmax],sz,r[nmax];
struct nodeq[nmax];
int getid(ll x)
bool cmp(node a, node b)
inline
void modify(int pos,ll val)
inline
void del(int pos)
int main()
if(belong[q[i].l] == belong[q[i].r])
q[i].ans = temp;
}else
}sort(q+1,q+1+m,cmpid);
for(int i = 1;i<=m;++i) printf("%lld\n",q[i].ans);
return
0;}
bzoj4241 歷史研究
這題也是坑了好久 之前whx帶我刷joi的時候本來應該要做的。可是太懶沒有寫。區間詢問加權眾數。分塊,預處理出塊和塊之間的答案,記錄到第i個塊數字x出現了多少次。然後查詢的時候和普通眾數基本一樣,就是乘了個權值而已。要離散化。時間複雜度o nlogn mn 昨晚寫的常數太爛了。用了struct,陣列...
BZOJ4241 歷史研究
一眼覺得是莫隊,發現刪除不是很好搞,於是上回滾莫隊直接搞過 回滾莫隊用於處理難以刪除但是易於新增 其實易於刪除難以新增也可以,但是沒見過這樣題 的莫隊,排序照常,如果左右端點在同一塊直接暴力,這部分最多n sqrt n,否則把左端點在一塊的一起處理,清空莫隊,然後直接令莫隊左端點在塊尾,這部分n s...
bzoj4241 歷史研究
題目鏈結 看到題目就聯想到了 bzoj2809 apio2012 dispatching。想了想權值分塊 莫隊,發現不好維護塊內最值,又看了看80s的時間,於是怒水一發線段樹 莫隊,結果先wa後tle,不斷tle,無論怎麼改常數都不行,難道nlogn sqrt n 就是過不了嗎!不爽,蒯個題解,再見...