[JOISC 2016 Day 3] 回转寿司 题解
又是一道满级性质题,第一次在分块里面打堆这种东西。
感觉做了一堆
首先这种神奇题目,还有这个神级时限,没有很好的办法处理的时候,我们考虑对序列分块,设块长为
环不用去管,纯粹就是懒得好好造数据,直接破开就可以了。
需要明确的一点是,如果一个数经过了一整块之后,那么这个数就会变成这个块的最大值。(前提是他变了。)
所以对于一个数在整块上的处理是比较简单的,维护一个大根堆,随时跟进这个块上有哪些数就行。然后操作的时候替换就可以了。
但是散块呢?
首先修改散块是非常简单的,就是暴力修。但是我们现在要思考的是如何去查询散块,因为你并没有在修改整块的时候跟进每个数的值。
我们仔细思考可以发现(???),对于两个数
那这个问题就会方便很多,我们可以对于每个块维护一个小根堆,表示整个块当前加入了哪些数。可以发现,我们为了得到一个散块的具体值,在暴力重构的时候,如果我们按照小根堆的顺序进行加入时,我们就可以直接从左到右枚举块上的所有数,如果这个数大于小根堆的根,那就把这个根删掉,然后将这个数加入小根堆后,替换为这个根(正确性由替换条件
总时间复杂度,整块由于存在替换,为
时限够大,
代码
#include <bits/stdc++.h>
using namespace std;
#define maxn 400005
int n, q, a[maxn];
int l[maxn], r[maxn], belong[maxn];
priority_queue<int> p1[705];
priority_queue<int, vector<int>, greater<int> > p2[705];
void init()
{
int len = sqrt(n);
for (int i = 1; i <= len; ++i)
{
l[i] = (i - 1) * len + 1, r[i] = i * len;
for (int j = l[i]; j <= r[i]; ++j) belong[j] = i;
}
if(len * len < n)
{
l[len + 1] = len * len + 1, r[len + 1] = n;
++len;
for (int j = l[len]; j <= n; ++j) belong[j] = len;
}
for (int i = 1; i <= len; ++i)
{
for (int j = l[i]; j <= r[i]; ++j)
p1[i].push(a[j]);
}
}
void rebuild(int p)
{
if(p2[p].empty()) return;
for (int i = l[p]; i <= r[p]; ++i)
{
if(a[i] > p2[p].top())
{
int x = p2[p].top(); p2[p].pop();
p2[p].push(a[i]), a[i] = x;
}
}
while(!p2[p].empty()) p2[p].pop();
}
int bruce(int p, int l, int r, int x)
{
while(!p1[p].empty()) p1[p].pop();
for (int i = l; i <= r; ++i) if(a[i] > x) swap(a[i], x);
for (int i = ::l[p]; i <= ::r[p]; ++i) p1[p].push(a[i]);
return x;
}
int query(int l, int r, int x)
{
int p = belong[l], q = belong[r];
rebuild(p), rebuild(q);
if(p == q) return bruce(p, l, r, x);
else
{
x = bruce(p, l, ::r[p], x);
for (int i = p + 1; i < q; ++i)
{
int y = p1[i].top();
if(y <= x) continue;
p1[i].pop(), p1[i].push(x), p2[i].push(x);
x = y;
}
return x = bruce(q, ::l[q], r, x);
}
}
int main()
{
scanf("%d %d", &n, &q);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
init();
while(q--)
{
int l, r, x;
scanf("%d %d %d", &l, &r, &x);
int ans;
if(l <= r) ans = query(l, r, x);
else ans = query(l, n, x), ans = query(1, r, ans);
printf("%d\n", ans);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】