模板【莫队】done
PART1(算法思想简介)
1.实现、dalao分析:
2.时间复杂度:
3.适用情况、特别优势、需要注意的点:
4.函数、变量名的解释+英文:
PART2(算法各种类型(并附上代码))
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** 莫队提供了这样一个排序方案:将原序列以根号下n为一块进行分块(分块的大小也珂以调整) **/ #pragma GCC optimize("O3") #include <bits/stdc++.h> #define N 100005 using namespace std; inline int read() { register int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x * f; } int v[N], blocksize = 0;//v:value , blocksize:分块大小 struct query { int l, r, id, bl;//l,r为左右区间编号,p是第几组查询的编号(记录下来为了排序后不打乱顺序还按照原查询的顺序输出),bl是分块数。 } q[N];//一个询问 int sum[N];//记录x这个数字出现过多少次了 bool ans[N];//i询问如果没有重复的赋值为true,否则为false int cnt = 0;//记录数字的种类 inline void add(register int x) { if (++sum[v[x]] == 1) ++cnt; } inline void del(register int x) { if (--sum[v[x]] == 0) --cnt; } inline bool cmp(register query a, register query b) { //排序第一关键字是询问的左端点所在块的编号,第二关键字是询问的右端点本身的位置,都是升序 //下就是一般的莫队排序 //return a.bl==b.bl?a.r<b.r:a.bl<b.bl; //又多出一种优化,叫做奇偶优化 //如果区间左端点所在块不同,那么就直接按左端点从小到大排;如果相同,奇块按右端点从小到大排,偶块按右端点从大到小排。 return a.bl != b.bl ? a.l < b.l : ((a.bl & 1) ? a.r < b.r : a.r > b.r); } int main() { //init memset(sum, 0, sizeof(sum)); //cin int n = read(), m = read(); for (register int i = 1; i <= n; ++i) v[i] = read(); //对询问按照分块排序 blocksize = sqrt(n); for (register int i = 1; i <= m; ++i) { int l = read(), r = read(); q[i] = (query){l, r, i, (l - 1) / blocksize + 1}; } sort(q + 1, q + m + 1, cmp); //窗口式更新1~m个节点的答案 int l = 1, r = 0; for (register int i = 1; i <= m; ++i) { int ll = q[i].l, rr = q[i].r;//目标区间 while (l < ll)//左端点包含多了 del(l++); while (l > ll)//做端点包含少了 add(--l); while (r < rr)//右端点包含少了 add(++r); while (r > rr)//右端点包含多了 del(r--); ans[q[i].id] = (cnt == rr - ll + 1) ? 1 : 0;//求出来若区间种类数cnt == 区间长度,就ok } for (register int i = 1; i <= m; ++i) if (ans[i]) puts("Yes"); else puts("No"); return 0; }
PART3(算法的延伸应用、深度的理解、相关的有趣题目)