洛谷 P1972 [SDOI2009]HH的项链【莫队算法学习】
P1972 [SDOI2009]HH的项链
题目背景
无
题目描述
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
输入输出格式
输入格式:第一行:一个整数N,表示项链的长度。
第二行:N 个整数,表示依次表示项链中贝壳的编号(编号为0 到1000000 之间的整数)。
第三行:一个整数M,表示HH 询问的个数。
接下来M 行:每行两个整数,L 和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
输出格式:M 行,每行一个整数,依次表示询问对应的答案。
输入输出样例
6 1 2 3 4 3 5 3 1 2 3 5 2 6
2 2 4
说明
数据范围:
对于100%的数据,N <= 50000,M <= 200000。
题目链接:https://www.luogu.org/problem/show?pid=1972
分析:莫队算法经典题,算是模版题吧!学习一下!
下面给出AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=1001010; 4 typedef long long ll; 5 int n,m,unit; 6 inline int read() 7 { 8 int x=0,f=1; 9 char ch=getchar(); 10 while(ch<'0'||ch>'9') 11 { 12 if(ch=='-') 13 f=-1; 14 ch=getchar(); 15 } 16 while(ch>='0'&&ch<='9') 17 { 18 x=x*10+ch-'0'; 19 ch=getchar(); 20 } 21 return x*f; 22 } 23 inline void write(int x) 24 { 25 if(x<0) 26 { 27 putchar('-'); 28 x=-x; 29 } 30 if(x>9) 31 { 32 write(x/10); 33 } 34 putchar(x%10+'0'); 35 } 36 struct Query 37 { 38 int L,R,id; 39 }node[maxn]; 40 ll gcd(ll a,ll b)///求最大公约数 41 { 42 return b==0?a:gcd(b,a%b); 43 } 44 struct Ans 45 { 46 ll a,b; 47 void reduce()///分数简化操作 48 { 49 ll d=gcd(a,b); 50 a/=d; 51 b/=d; 52 } 53 }ans[maxn]; 54 bool cmp(Query a,Query b)///把1~n分成sqrt(n)段,unit=sqrt(n)m个查询先按照第几个块排序,再按照R排序,分块处理 55 { 56 if(a.L/unit!=b.L/unit) 57 return a.L/unit<b.L/unit; 58 else return a.R<b.R; 59 } 60 int a[maxn]; 61 int num[maxn]; 62 inline void work() 63 { 64 ll temp=0; 65 memset(num,false,sizeof(num)); 66 int L=1; 67 int R=0; 68 for(int i=0;i<m;i++)///莫队算法核心部分 69 { 70 while(R<node[i].R) 71 { 72 R++; 73 ///temp-=(ll)num[a[R]]*num[a[R]]; 74 ///num[a[R]]++; 75 ///temp+=(ll)num[a[R]]*num[a[R]]; 76 if(!num[a[R]]) 77 temp++; 78 num[a[R]]++; 79 } 80 while(R>node[i].R) 81 { 82 ///temp-=(ll)num[a[R]]*num[a[R]]; 83 num[a[R]]--; 84 ///temp+=(ll)num[a[R]]*num[a[R]]; 85 ///R--; 86 if(!num[a[R]]) 87 temp--; 88 R--; 89 } 90 while(L<node[i].L) 91 { 92 ///temp-=(ll)num[a[L]]*num[a[L]]; 93 num[a[L]]--; 94 ///temp+=(ll)num[a[L]]*num[a[L]]; 95 ///L++; 96 if(!num[a[L]]) 97 temp--; 98 L++; 99 } 100 while(L>node[i].L) 101 { 102 L--; 103 ///temp-=(ll)num[a[L]]*num[a[L]]; 104 ///num[a[L]]++; 105 ///temp+=(ll)num[a[L]]*num[a[L]]; 106 if(!num[a[L]]) 107 temp++; 108 num[a[L]]++; 109 } 110 ans[node[i].id].a=temp; 111 ///ans[node[i].id].b=(ll)(R-L+1)*(R-L); 112 ///ans[node[i].id].reduce(); 113 } 114 } 115 int main() 116 { 117 n=read(); 118 for(int i=1;i<=n;i++) 119 a[i]=read(); 120 m=read(); 121 for(int i=0;i<m;i++) 122 { 123 node[i].id=i; 124 node[i].L=read(); 125 node[i].R=read(); 126 } 127 unit=(int)sqrt(n); 128 sort(node,node+m,cmp); 129 work(); 130 for(int i=0;i<m;i++) 131 printf("%lld\n",ans[i].a); 132 return 0; 133 }
作 者:Angel_Kitty
出 处:https://www.cnblogs.com/ECJTUACM-873284962/
关于作者:阿里云ACE,目前主要研究方向是Web安全漏洞以及反序列化。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
欢迎大家关注我的微信公众号IT老实人(IThonest),如果您觉得文章对您有很大的帮助,您可以考虑赏博主一杯咖啡以资鼓励,您的肯定将是我最大的动力。thx.
我的公众号是IT老实人(IThonest),一个有故事的公众号,欢迎大家来这里讨论,共同进步,不断学习才能不断进步。扫下面的二维码或者收藏下面的二维码关注吧(长按下面的二维码图片、并选择识别图中的二维码),个人QQ和微信的二维码也已给出,扫描下面👇的二维码一起来讨论吧!!!
欢迎大家关注我的Github,一些文章的备份和平常做的一些项目会存放在这里。