P1972 [SDOI2009]HH的项链
第一道莫队,日常抄题解。。
luogu上面数据加强了,最后两个点莫队跑不过是最骚的。
但是不妨碍我写随笔。。。
莫队算法思想就是给你两个神奇的指针l和r,然后通过排序使得他们尽量为\(O(1)\)地跳完整个答案。
显然是个离线算法,但是只要搞出来就ok了呀。
代码参考的是Menci大佬的:https://oi.men.ci/sdoi2009-diff/
话说两次排序跟一次排序用的时间是差不多的?
代码:
#include<cstdio>
#include<cmath>
#include<algorithm>
const int maxn = 500005;
const int maxN = 1005;
const int maxm = 1000005;
struct Nodes
{
int l, r, idx;
} q[maxn];
int a[maxn];
int belong[maxn], ll[maxN], rr[maxN];
int len, num;
int cnt[maxm];
int ans[maxn];
int n, m;
int l = 1, r = 0, sum = 0;
int read()
{
int ans = 0, s = 1;
char ch = getchar();
while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') ans = (ans << 3) + (ans << 1) + ch - '0', ch = getchar();
return s * ans;
}
bool cmp1(const Nodes x, const Nodes y)
{
if(belong[x.l] == belong[y.l]) return x.r < y.r;
return belong[x.l] < belong[y.l];
}
bool cmp2(const Nodes x, const Nodes y)
{
return x.idx < y.idx;
}
void init()
{
len = sqrt(n);
for(int i = 1; i <= m; i++) belong[i] = (i - 1) / len + 1;
}
void add(int x)
{
x = a[x];
if(cnt[x] == 0) sum++;
cnt[x]++;
}
void del(int x)
{
x = a[x];
if(cnt[x] == 1) sum--;
cnt[x]--;
}
int extend(int l, int r, bool right, bool add)//大佬说这里是莫队修改模板
{
if(right)
{
if(add)
{
cnt[a[r]]++;
if(cnt[a[r]] == 1) return 1;
else return 0;
}
else
{
cnt[a[r]]--;
if(cnt[a[r]] == 0) return -1;
else return 0;
}
}
else
{
if(add)
{
cnt[a[l]]++;
if(cnt[a[l]] == 1) return 1;
else return 0;
}
else
{
cnt[a[l]]--;
if(cnt[a[l]] == 0) return -1;
else return 0;
}
}
}
void solve()//莫队算法核心
{
for(int i = 1; i <= m; i++)
{
int ql = q[i].l, qr = q[i].r;
while(r < qr) sum += extend(l, ++r, 1, 1);
while(r > qr) sum += extend(l, r--, 1, 0);
while(l > ql) sum += extend(--l, r, 0, 1);//r已经到达目的地,向左跳答案要加
while(l < ql) sum += extend(l++, r, 0, 0);//同理要减
ans[q[i].idx] = sum;
}
}
int main()
{
n = read();
for(int i = 1; i <= n; i++) a[i] = read();
m = read();
for(int i = 1; i <= m; i++) q[i].l = read(), q[i].r = read(), q[i].idx = i;
init();
std::sort(q + 1, q + m + 1, cmp1);
solve();
for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);
return 0;
}