今天研究一道毒瘤题(好吧是我太弱了) 偶然间了解到莫队这个暴力操作,hale赶紧去学了学
哎呀我去,这玩意真的强,不愧为优雅的暴力算法
先放一道例题
这道题完美的给我们诠释了莫队是多么的优雅
看题发现这玩意很难搞,线段树怎么维护啊,开始搜题解,嘤嘤嘤
忽然看了眼标签莫队。。。
那学一学吧
进入正题:
一、什么是莫队
好吧,百度上没有这玩意的官方百科,自己想法学吧
莫队是莫涛队长在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; }
愿大家都越来越强