[BZOJ3781][P2709]小B的询问[莫队]
Posted ycrpro
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3781][P2709]小B的询问[莫队]相关的知识,希望对你有一定的参考价值。
入门题
对于一个区间的询问,如果在已知\\([l,r]\\)的答案时可以用O(1)的时间求出左右端点\\(±1\\)的答案,就可以使用莫队来优化。
设已知区间为\\([l_1,r_1]\\),所求区间为\\([l_2,r_2]\\)
可知求得\\([l_2,r_2]\\)的成本是\\(|l_1-l_2| + |r_1-r_2|\\)如果把这两个区间看成点,这个成本就是两点的曼哈顿距离,
对于多个询问,求出曼哈顿距离最小生成树就可以以最小成本获得答案,使用一种奇怪的方式 ——sort来获得最优的转移方式 我并不知道原理
对于整个区间进行分块,每个询问按照块编号为第一关键字,右端点为第二关键字进行排序,然后依次处理每个询问即可。看起来还是很暴力
卡常技巧我仍然不知道为什么:块大小\\(\\frac{n}{\\sqrt{m*\\frac{2}{3}}}\\)比\\(\\sqrt n\\)更快,sort时对于同一块里的询问按照奇偶排序更快
效果图
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 50005; typedef long long LL;
struct Data{
int l, r, id, pos;
inline bool operator < (const Data & rhs) const {
return pos ^ rhs.pos ? pos < rhs.pos : pos&1?r<rhs.r:r>rhs.r;
// if (pos == rhs.pos) return r < rhs.r;
// return pos < rhs.pos;
}
}d[MAXN];
int b[MAXN], a[MAXN], n, m, k, cnt[MAXN];LL anss[MAXN];
int main(void) {
scanf("%d%d%d", &n, &m, &k);
int block = n/sqrt(m*2/3);
for(int i = 1; i <= n; ++i) scanf("%d", a+i);
for(int i = 1; i <= m; ++i) {
scanf("%d%d", &d[i].l, &d[i].r); d[i].id = i;
d[i].pos = (d[i].l-1)/block + 1;
}
sort(d+1, d+m+1);
int l = 1, r = 0; LL ans = 0;
for(int i = 1; i <= m; ++i) {
while (l > d[i].l) l--, cnt[a[l]]++, ans += 2*cnt[a[l]] - 1;
while (r < d[i].r) r++, cnt[a[r]]++, ans += 2*cnt[a[r]] - 1;
while (l < d[i].l) cnt[a[l]]--, ans -= 2*cnt[a[l]] + 1, l++;
while (r > d[i].r) cnt[a[r]]--, ans -= 2*cnt[a[r]] + 1, r--;
anss[d[i].id] = ans;
}
for(int i = 1; i <= m; ++i) printf("%lld\\n", anss[i]);
return 0;
}
以上是关于[BZOJ3781][P2709]小B的询问[莫队]的主要内容,如果未能解决你的问题,请参考以下文章