标签:rpos 回滚 P5906 int lpos blpos 莫队 dis
题目链接: P5906 回滚莫队&不删除莫队
大致题意
给定一个序列,多次询问一段区间 [ l , r ] [l,r] [l,r],求区间中相同的数的最远间隔距离。
序列中两个元素的间隔距离指的是两个元素下标差的绝对值。 (ctrl+c, ctrl+v)
解题思路
回滚莫队
考虑信息维护: 我们需要记录每个值出现的最左和最右位置.
下文 [ L , R ] [L, R] [L,R]为莫队维护区间, [ l , r ] [l, r] [l,r]为查询区间.
由于 l l l在一个块内时, r r r是单调递增的, 因此我们会不断更新最右位置. 贡献为: 最左位置和当前位置的距离.
考虑暴力维护 [ l , L − 1 ] [l, L - 1] [l,L−1]的部分, 当 v a l val val第一次出现在 [ l , L − 1 ] [l, L - 1] [l,L−1]时, 贡献为: 最右位置和当前位置的距离. 否则为: 最左位置和当前位置的距离.
我们发现这部分我们会改变最左位置的信息, 因此我们应当备份 [ L , R ] [L, R] [L,R]区间最左位置的信息.
为什么我的代码比别人高一倍的常数QAQ
AC代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 2E5 + 10; int B;
int w[N];
vector<int> v(1, -0x3f3f3f3f); // 离散化
int find(int x) { return lower_bound(v.begin(), v.end(), x) - v.begin(); }
struct mo {
int l, r, id;
bool operator< (const mo& t) const {
if (l / B != t.l / B) return l < t.l;
return r < t.r;
}
}; vector<mo> area;
int res[N];
int lpos[N], rpos[N], blpos[N], dis;
void add(int x) { //向右添加
if (lpos[w[x]]) dis = max(dis, x - lpos[w[x]]), rpos[w[x]] = x;
else lpos[w[x]] = rpos[w[x]] = x;
}
void bruth(int l, int r, int id) {
for (int i = l; i <= r; ++i) add(i);
res[id] = dis;
for (int i = l; i <= r; ++i) lpos[w[i]] = rpos[w[i]] = 0;
dis = 0;
}
int main()
{
int n; scanf("%d", &n);
B = sqrt(n);
rep(i, n) scanf("%d", &w[i]), v.push_back(w[i]);
sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end());
rep(i, n) w[i] = find(w[i]), blpos[w[i]] = -1;
int m; cin >> m;
rep(i, m) {
int l, r; scanf("%d %d", &l, &r);
area.push_back({ l, r, i });
}
sort(area.begin(), area.end());
int L = 1, R = 0, last = -1;
for (auto& [l, r, id] : area) {
if (l / B != last) {
for (int i = L; i <= R; ++i) {
lpos[w[i]] = rpos[w[i]] = 0;
}
dis = 0;
L = (l / B + 1) * B, R = L - 1, last = l / B;
}
if (l / B == r / B) {
bruth(l, r, id);
continue;
}
while (R < r) add(++R);
int bdis = dis;
for (int i = l; i <= L - 1; ++i) {
if (blpos[w[i]] == -1) { //没有备份过
blpos[w[i]] = lpos[w[i]]; //备份
lpos[w[i]] = i;
if (rpos[w[i]]) dis = max(dis, rpos[w[i]] - i);
}
else dis = max(dis, i - lpos[w[i]]);
}
res[id] = dis;
for (int i = l; i <= L - 1; ++i) {
if (blpos[w[i]] != -1) {
lpos[w[i]] = blpos[w[i]], blpos[w[i]] = -1;
}
}
dis = bdis;
}
rep(i, m) printf("%d\n", res[i]);
return 0;
}
END
标签:rpos,回滚,P5906,int,lpos,blpos,莫队,dis 来源: https://blog.csdn.net/weixin_45799835/article/details/120458750
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。