【洛谷P1972】【BZOJ1878】HH的项链【莫队】
题目大意:
题目链接:
洛谷:https://www.luogu.org/problemnew/show/P1972
BZOJ:https://www.lydsy.com/JudgeOnline/problem.php?id=1878
给出一个序列,询问中有多少个不同数字。
思路:
莫队裸题。其实就是 这道题 的弱化版(不用修改)
但是这道题卡莫对。开会MLE。
莫队方法就不讲了,相信大家都会。这里就讲一下如何用莫队卡过这道题。
- 输入输出优化
- 块长
- 合并语句。
这样可以大大提高程序的效率。除了码风奇丑意外都还好
到此为止程序可以卡进。最初始的莫队是的。
实在不知道怎么剪了。于是看了一下卡过的莫队代码。
发现他们的排序都没有用,而是搞了个这个
bool operator < (const Ask &a,const Ask &b){
return pos[a.l]^pos[b.l] ? a.l<b.l : pos[a.l]&1 ? a.r<b.r:a.r>b.r;
}
从条件语句中看,这个显然是代替的。
而且可以大大加快速度。具体原因我也不知道。
- 加上这个玄学优化。
- 开洛谷自带。
这样就可以很稳的过掉这道题了。
可以看到最慢点内,已经算是很快的了。
代码:
// luogu-judger-enable-o2
#include <cmath>
#include <ctime>
#include <cstdio>
#include <string>
#include <algorithm>
#define reg register
using namespace std;
const int N=500010,M=1000010;
int n,m,l,r,sum,T,a[N],cnt[M],pos[N],ans[N];
struct Ask
{
int l,r,id;
}ask[N];
bool operator < (const Ask &a,const Ask &b)
{
return pos[a.l]^pos[b.l] ? a.l<b.l : pos[a.l]&1 ? a.r<b.r:a.r>b.r;
}
inline int read()
{
int d=0;
char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch))
d=(d<<3)+(d<<1)+ch-48,ch=getchar();
return d;
}
inline void write(int x)
{
if (x>9) write(x/10);
putchar(x%10+48);
}
int main()
{
n=read();
T=1250;
for (reg int i=1;i<=n;++i)
{
a[i]=read();
pos[i]=(i-1)/T+1;
}
m=read();
for (reg int i=1;i<=m;++i)
{
ask[i].l=read(); ask[i].r=read();
ask[i].id=i;
}
sort(ask+1,ask+1+m);
l=1;
for (reg int i=1;i<=m;++i)
{
while(l>ask[i].l) sum+=(++cnt[a[--l]]==1);
while(l<ask[i].l) sum-=(--cnt[a[l++]]==0);
while(r>ask[i].r) sum-=(--cnt[a[r--]]==0);
while(r<ask[i].r) sum+=(++cnt[a[++r]]==1);
ans[ask[i].id]=sum;
}
for (reg int i=1;i<=m;++i)
write(ans[i]),putchar(10);
return 0;
}