莫队算法

Posted ivan-count

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了莫队算法相关的知识,希望对你有一定的参考价值。

原理

1、离线操作。

2、划分成若干块,将区间先按块排序,块内按区间右边界排序。块大小一般为sqrt(n)。

3、按照排序后的区间进行操作,不断进行区间转移,更新答案。

题目

1、小Z的袜子(hose) HYSBZ - 2038

  题意:有n只袜子,求区间内颜色相同的两只袜子的概率。

  思路:对于区间[l,r],其概率为sum(cnt[i]*(cnt[i-1])|i∈val[l,..,r])/[(r-l+1)*(r-l)]。按照莫队的思想更新分子即可。

技术分享图片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 const int maxn = 5e5 + 10;
 7 const int maxm = 5e5 + 10;
 8 int n, m;
 9 int unit_len;
10 int be[maxn];//记录下标L属于哪一个分块
11 int val[maxn];
12 int cnt[maxn];
13 long long  ans;
14 long long ansa[maxn],ansb[maxn]; //答案a / b
15 struct node
16 {
17     int l, r,id;//区间[l,r]、输入顺序
18     friend bool operator<(const node&n1, const node&n2)
19     {
20         if (be[n1.l] == be[n2.l]) return n1.r < n2.r;
21         else return n1.l < n2.l;
22     }
23 }qs[maxm];
24 long long GCD(long long a, long long b)
25 {
26     if (a < b) swap(a, b);
27     while (b)
28     {
29         long long tmp = a % b;
30         a = b;
31         b = tmp;
32     }
33     return a;
34 }
35 long long cal(int x)
36 {
37     return 1ll * x*(x - 1);
38 }
39 void update(int pos, int v)
40 {
41     ans -= cal(cnt[val[pos]]);
42     cnt[val[pos]] += v;
43     ans += cal(cnt[val[pos]]);
44 }
45 void solve()
46 {
47     int l = 1, r = 0;
48     ans = 0;
49     for (int i = 1; i <= m; i++)
50     {
51         int id = qs[i].id;
52         while (r < qs[i].r) update(r + 1, 1), r++;
53         while (r > qs[i].r) update(r, -1),r--;
54         while (l < qs[i].l) update(l, -1), l++;
55         while (l > qs[i].l) update(l - 1, 1), l--;
56         if (ans == 0) ansa[id] = 0, ansb[id] = 1;
57         else
58         {
59             ansb[id]= cal(qs[i].r - qs[i].l + 1);
60             ansa[id]= ans;
61             long long gcd = GCD(ansa[id],ansb[id]);
62             ansa[id]/= gcd;
63             ansb[id] /= gcd;
64         }
65     }
66 }
67 int main()
68 {
69     while (~scanf("%d%d", &n, &m))
70     {
71         unit_len = sqrt(n);
72         for (int i = 1; i <= n; i++) scanf("%d", &val[i]);
73         for (int i = 1; i <= n; i++) be[i] = i / unit_len + 1;
74         for (int i = 1; i <= m; i++) scanf("%d%d", &qs[i].l, &qs[i].r),qs[i].id=i;
75         sort(qs + 1, qs + 1 + m);
76         solve();
77         for (int i = 1; i <= m; i++)
78         {
79             printf("%lld/%lld
", ansa[i], ansb[i]);
80         }
81     }
82 
83 
84     return 0;
85 }
View Code

 

以上是关于莫队算法的主要内容,如果未能解决你的问题,请参考以下文章

CSU 1515 Sequence (莫队算法)

CodeForces - 220B 离散化+莫队算法

算法笔记莫队算法(基础莫队,带修莫队,回滚莫队,树上莫队,二次离线莫队)

莫队算法~讲解

P1494 [国家集训队]小Z的袜子(莫队算法)

莫队