莫队——学习笔记

今天研究一道毒瘤题(好吧是我太弱了) 偶然间了解到莫队这个暴力操作,hale赶紧去学了学

哎呀我去,这玩意真的强,不愧为优雅的暴力算法

先放一道例题

mo题

这道题完美的给我们诠释了莫队是多么的优雅

看题发现这玩意很难搞,线段树怎么维护啊,开始搜题解,嘤嘤嘤

忽然看了眼标签莫队。。。

那学一学吧

进入正题:

一、什么是莫队

好吧,百度上没有这玩意的官方百科,自己想法学吧

莫队是莫涛队长在2009年提出的算法,算法复杂度为0(n 3/2)相较于线段树有一定劣势,但是他没有大常数啊,嘿嘿嘿

怎么搞呢?

主要思想:先暴力求出一段区间的问题的答案,然后通过左右指针的移动来实现,为了保证每次移动的尽可能的快,应该实行分块,对询问的左指针进行排序,如若在一个块里就进行第二关键字——右指针大小进行排序,这样的话得到的就是一个二维图象上的曼哈顿距离最小树;

struct node
{ int l,r,pos,id;
  bool operator<(const node &x) const 
  { return (x.pos==pos)?x.r<r:x.pos<pos;
  }
} a[N];

二、指针的移动,原理很是简单的了,大家拿张可爱的演草纸,手动模拟一下下就好了

while (a[i].l<l) {l--;cnt[b[l]]++;ans+=(2*cnt[b[l]]-1);}
while (a[i].r>r) {r++;cnt[b[r]]++;ans+=(2*cnt[b[r]]-1);}
while (a[i].l>l) {cnt[b[l]]--;ans-=(2*cnt[b[l]]+1);l++;}
while (a[i].r<r) {cnt[b[r]]--;ans-=(2*cnt[b[r]]+1);r--;}


三、讲完了,哈哈哈

直接放上去代码了

#include<bits/stdc++.h>
using namespace std;
const int N=2000010;
int m,n,k,p;
int cnt[N],b[N];
long long put[N];
struct node
{ int l,r,pos,id;
  bool operator<(const node &x) const 
  { return (x.pos==pos)?x.r<r:x.pos<pos;
  }
} a[N];
int main()
{ scanf("%d%d%d",&n,&m,&k);
  int size=(int)sqrt(n);
  for (int i=1;i<=n;i++) scanf("%d",&b[i]);
  for (int i=1;i<=m;i++) {scanf("%d%d",&a[i].l,&a[i].r);a[i].pos=(a[i].l-1)/size+1;a[i].id=i;}
  sort(a+1,a+m+1);
  int l=1,r=0;
  long long ans=0;
  for (int i=1;i<=m;i++)
  { while (a[i].l<l) {l--;cnt[b[l]]++;ans+=(2*cnt[b[l]]-1);}
    while (a[i].r>r) {r++;cnt[b[r]]++;ans+=(2*cnt[b[r]]-1);}
    while (a[i].l>l) {cnt[b[l]]--;ans-=(2*cnt[b[l]]+1);l++;}
    while (a[i].r<r) {cnt[b[r]]--;ans-=(2*cnt[b[r]]+1);r--;}
    put[a[i].id]=ans;
  }
  for (int i=1;i<=m;i++)
  printf("%lld
",put[i]);
  return 0;
}

愿大家都越来越强

慢即是快,细则是能,于小处铸迤逦
原文地址:https://www.cnblogs.com/Hale522520/p/10351181.html