• 模板【莫队】done


    PART1(算法思想简介

    1.实现、dalao分析

    从入门到精通(优)

    一般莫队的详细理解、为啥要分块 还得看这里(优)

    回滚莫队

    回滚莫队2 :就是把l定住,这样r就是递增的了

    2.时间复杂度

    3.适用情况、特别优势需要注意的点

    4.函数、变量名的解释+英文

    PART2(算法各种类型(并附上代码)

     题目

    /**
    莫队提供了这样一个排序方案:将原序列以根号下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(算法的延伸应用、深度的理解、相关的有趣题目

  • 相关阅读:
    BZOJ 2653 middle
    BZOJ 3207 花神的嘲讽计划Ⅰ
    BZOJ 3689 异或之
    BZOJ 3037 创世纪
    BZOJ [1264] [ AHOI2006]基因匹配Match
    BZOJ 2186 [Sdoi2008]沙拉公主的困惑
    BZOJ 3362 Navigation Nightmare
    BZOJ 3209 花神的数论题
    BZOJ 1411 ZJOI2009 硬币游戏
    【HDU1573】X问题
  • 原文地址:https://www.cnblogs.com/bear-xin/p/15030330.html
Copyright © 2020-2023  润新知