码迷,mamicode.com
首页 > 编程语言 > 详细

莫队算法学习

时间:2018-06-23 22:43:56      阅读:201      评论:0      收藏:0      [点我收藏+]

标签:题目   TE   ace   lap   add   space   problems   algo   http   

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

先来看板子题:CF86D. Powerful array

题意:给你n个数,m次询问,$K_s$为区间内s的数目,求区间[L,R]之间所有$K_s*K_s*s$的和。($1\leq n,m\leq 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\n", q[i].ans);
66     }
67     return 0;
68 }
View Code

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

题意:给你一棵树n个点,m次询问($n\leq 100000,m\leq 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\n", q[i].ans);
86     }
87     return 0;
88 }
View Code

 

莫队算法学习

标签:题目   TE   ace   lap   add   space   problems   algo   http   

原文地址:https://www.cnblogs.com/NineSwords/p/9218820.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!