[Violet]蒲公英
作者:互联网
[Violet]蒲公英
强制在线求区间众数。
思路
与一些分块题不同,本题并没有在块内插入其他东西进行维护,最朴素的分块。类似【作诗】的预处理,预先处理出每个数出现的块后缀和(前缀和应该也没有问题),以及块间的众数。对于[l,r]位于的块是挨着或在同一块的情况,直接暴力处理(挨着的不太好处理),其余的按照分块的正常思路进行。显然,[l,r]的众数一定是整块的众数或者散块中出现的数。注意细节:要输出的是离散化前的编号,以及这里是后缀和,别还原成了前缀和。
代码
memset
又一次拖慢近5倍。
inline void INIT()
{
len = sqrt(n);t = n / len;
for(int i = 1;i <= t;i++){
L[i] = (i - 1) * len + 1;
R[i] = i * len;
}
R[t] = n;
block[n + 1] = n + 1;
for(int i = 1;i <= t;i++)
for(int j = L[i];j <= R[i];j++) block[j] = i;
for(int i = 1;i <= t;i++){
int mx = 0;
for(int j = L[i];j <= n;j++){
cnt[i][a[j]]++;
if(cnt[i][mx] < cnt[i][a[j]] || (cnt[i][mx] == cnt[i][a[j]] && a[j] < mx)) mx = a[j];
if(block[j] != block[j + 1]) res[i][block[j]] = mx;
}
}
}
signed main()
{
n = read();m = read();
for(int i = 1;i <= n;i++) a[i] = read(),b[i] = a[i];
sort(b + 1,b + 1 + n);
tot = unique(b + 1,b + 1 + n) - b - 1;
for(int i = 1;i <= n;i++) a[i] = lower_bound(b + 1,b + 1 + tot,a[i]) - b;
INIT();
while(m--)
{
LL l,r;ans = 0;
scanf("%lld%lld",&l,&r);
l = (l + lstans - 1) % n + 1,r = (r + lstans - 1) % n + 1;
if(l > r) swap(l,r);
if(block[l] + 1 >= block[r]){
for(int i = l;i <= r;i++){
num[a[i]]++;
if(num[ans] < num[a[i]] || (num[ans] == num[a[i]] && a[i] < ans)) ans = a[i];
}
lstans = b[ans];
write(lstans);putchar('\n');
for(int i = l;i <= r;i++) num[a[i]]--;
continue;
}
ans = res[block[l] + 1][block[r] - 1];
int all = cnt[block[l] + 1][ans] - cnt[block[r]][ans];
for(int i = l;i <= R[block[l]];i++){
num[a[i]]++;
if(num[ans] + all < num[a[i]] + cnt[block[l] + 1][a[i]] - cnt[block[r]][a[i]] ||
(num[ans] + all == num[a[i]] + cnt[block[l] + 1][a[i]] - cnt[block[r]][a[i]] && a[i] < ans))
ans = a[i],all = cnt[block[l] + 1][a[i]] - cnt[block[r]][a[i]];
}
for(int i = L[block[r]];i <= r;i++){
num[a[i]]++;
if(num[ans] + all < num[a[i]] + cnt[block[l] + 1][a[i]] - cnt[block[r]][a[i]] ||
(num[ans] + all == num[a[i]] + cnt[block[l] + 1][a[i]] - cnt[block[r]][a[i]] && a[i] < ans))
ans = a[i],all = cnt[block[l] + 1][a[i]] - cnt[block[r]][a[i]];
}
lstans = b[ans];
write(lstans);putchar('\n');
for(int i = l;i <= R[block[l]];i++) num[a[i]]--;
for(int i = L[block[r]];i <= r;i++) num[a[i]]--;
}
return 0;
}
标签:分块,int,Violet,len,众数,蒲公英,block 来源: https://www.cnblogs.com/shijiazhuang-li/p/15244432.html