• 莫队算法学习


    慢慢的开始重新学习以前的算法了,先从莫队算法学起。ACM反正可以用板子,所以先功利一点,与AC题目无关的细节就不管了,以后有机会再补证明。

    先来看板子题:CF86D. Powerful array

    题意:给你n个数,m次询问,$K_s$为区间内s的数目,求区间[L,R]之间所有$K_s*K_s*s$的和。($1leq n,mleq 200000,a_i leq 10^6$)

    做法:先给序列分个块,按下标每$sqrt{n}$个数分一块。然后将询问离线后排个序,排序的方法为先按L所在的块的标号从小到大排,对于L所在的块的标号相同的,按照R从小到大排。然后在一一走就好了。

    复杂度比较好理解,为$O((m + n)sqrt{n})$。

     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <iostream>
     5 #include <algorithm>
     6 using namespace std;
     7 typedef long long ll;
     8 const int LEN = 2e5 + 5;
     9 ll ans;
    10 int i, j, k, n, m, s, t, S, l, r;
    11 int a[LEN], pos[LEN], num[1000005];
    12 struct node {
    13     int l, r, id;
    14     ll ans;
    15 } q[LEN];
    16 bool cmp(const node &x, const node &y) {
    17     return pos[x.l] < pos[y.l] || (pos[x.l] == pos[y.l] && x.r < y.r);
    18 }
    19 bool cmp2(const node &x, const node &y) {
    20     return x.id < y.id;
    21 }
    22 ll sqr(ll x) {
    23     return x * x;
    24 }
    25 void add(int x) {
    26     ans -= sqr(num[x]) * x;
    27     num[x]++;
    28     ans += sqr(num[x]) * x;
    29 }
    30 void del(int x) {
    31     ans -= sqr(num[x]) * x;
    32     num[x]--;
    33     ans += sqr(num[x]) * x;
    34 }
    35 int main() {
    36     scanf("%d %d", &n, &m);
    37     S = sqrt(n);
    38     for (int i = 1; i <= n; i++) {
    39         scanf("%d", &a[i]);
    40         pos[i] = (i - 1) / S + 1;
    41     }
    42     for (int i = 1; i <= m; i++) {
    43         scanf("%d %d", &q[i].l, &q[i].r);
    44         q[i].id = i;
    45     }
    46     sort(q + 1, q + 1 + m, cmp);
    47     l = 1, r = 0;
    48     for (int i = 1; i <= m; i++) {
    49         while (r < q[i].r) {
    50             add(a[++r]);
    51         }
    52         while (r > q[i].r) {
    53             del(a[r--]);
    54         }
    55         while (l < q[i].l) {
    56             del(a[l++]);
    57         }
    58         while (l > q[i].l) {
    59             add(a[--l]);
    60         }
    61         q[i].ans = ans;
    62     }
    63     sort(q + 1, q + 1 + m, cmp2);
    64     for (int i = 1; i <= m; i++) {
    65         printf("%I64d
    ", q[i].ans);
    66     }
    67     return 0;
    68 }
    View Code

     接下来是一道练习题:CF375D. Tree and Queries

    题意:给你一棵树n个点,m次询问($nleq 100000,mleq 100000$),每个节点有一种颜色, 每次询问问你以v节点为根的子树中,满足同一种颜色的个数$geq k$的颜色有几个。

    ps:这道题莫队并不是最优的做法,还有log的做法,暂时不讨论。

    做法:看起来是一道树上的题目,但是还是可以转化成序列上的来做。将树的dfs序搞出来,然后就是序列上[L,R]之间的询问,用数组维护一下颜色的个数几颗。

    本题作为CFDiv1的D题算是简单的了,事实上现场A的人也很多。

     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <iostream>
     5 #include <algorithm>
     6 using namespace std;
     7 const int LEN = 1e5 + 5;
     8 int i, j, k, n, m, s, t, ans, tot, Time, S, l, r;
     9 struct node {
    10     int l, r, k, ans, id;
    11 } q[LEN];
    12 struct edge {
    13     int vet, next;
    14 } E[LEN];
    15 int tid[LEN], a[LEN], size[LEN], num[LEN], sum[LEN], pos[LEN], head[LEN], to[LEN];
    16 void add(int u, int v) {
    17     E[++tot] = (edge){v, head[u]};
    18     head[u] = tot;
    19 }
    20 bool cmp(const node &x, const node &y) {
    21     return pos[x.l] < pos[y.l] || (pos[x.l] == pos[y.l] && x.r < y.r);
    22 }
    23 bool cmp2(const node &x, const node &y) {
    24     return x.id < y.id;
    25 }
    26 void dfs(int u, int pre) {
    27     size[u] = 1;
    28     tid[u] = ++Time;
    29     to[Time] = u;
    30     for (int e = head[u]; e != -1; e = E[e].next) {
    31         int v = E[e].vet;
    32         if (v != pre) {
    33             dfs(v, u);
    34             size[u] += size[v];
    35         }
    36     }
    37 }
    38 void add(int x) {
    39     num[x]++;
    40     sum[num[x]]++;
    41 }
    42 void del(int x) {
    43     sum[num[x]]--;
    44     num[x]--;
    45 }
    46 int main() {
    47     memset(head, -1, sizeof(head));
    48     scanf("%d %d", &n, &m);
    49     S = sqrt(n);
    50     for (int i = 1; i <= n; i++) {
    51         scanf("%d", &a[i]);
    52         pos[i] = (i - 1) / S + 1;
    53     }
    54     for (int i = 1; i < n; i++) {
    55         int x, y;
    56         scanf("%d %d", &x, &y);
    57         add(x, y);
    58         add(y, x);
    59     }
    60     dfs(1, -1);
    61     for (int i = 1; i <= m; i++) {
    62         int v, k;
    63         scanf("%d %d", &v, &k);
    64         q[i] = (node){tid[v], tid[v] + size[v] -1, k, 0, i};
    65     }
    66     sort(q + 1, q + 1 + m, cmp);
    67     l = 1, r = 0;
    68     for (int i = 1; i <= m; i++) {
    69         while (r < q[i].r) {
    70             add(a[to[++r]]);
    71         }
    72         while (r > q[i].r) {
    73             del(a[to[r--]]);
    74         }
    75         while (l < q[i].l) {
    76             del(a[to[l++]]);
    77         }
    78         while (l > q[i].l) {
    79             add(a[to[--l]]);
    80         }
    81         q[i].ans = sum[q[i].k];
    82     }
    83     sort(q + 1, q + 1 + m, cmp2);
    84     for (int i = 1; i <= m; i++) {
    85         printf("%d
    ", q[i].ans);
    86     }
    87     return 0;
    88 }
    View Code
  • 相关阅读:
    git stash错误小记
    PHP,Mysql根据经纬度计算距离并排序
    JS~字符串长度判断,超出进行自动截取(支持中文)
    Redis的三种启动方式
    Ubuntu 14.04 LTS下安装Google Chrome浏览器
    PHP-PHPExcel用法详解
    git设置log的别名 for hist log样式格式化
    Ubuntu系统下配置PHP支持SQLServer 2005
    Git命令图片版
    《一线架构师实践指南》读后感(二)
  • 原文地址:https://www.cnblogs.com/NineSwords/p/9218820.html
Copyright © 2020-2023  润新知