首页 > 代码库 > 莫队算法
莫队算法
特意学了一下莫队算法,做了几个题,总结一下。
目前还只是学了线性序列的莫队的分块,没有学什么曼哈顿最小生成树。分开的写法也挺简单粗暴明了(据说曼哈顿距离的最小生成树并不好写)
时间复杂度是O(n*sqrt(n))。
做了几个题感觉莫队最主要的还是三个内容
1、离线
2、分块计算
3、由[l,r]到[l+1,r] or [l,r+1] or [l-1,r] or [l,r-1]可以在O(1)(ps:O(logn)应该也可以)内求出,且必须能在O(1)内求出
序列型 莫队算法 分块过程基本上都是一样的,把整个序列按照index从小到大分成sqrt(n)块,记录下序列中每个元素所在的块,把离线后的询问按照 左端点 l 所在块 为第一关键字,右端点 r 为第二关键字排序。这样排序比直接以左端点l 和右端点r排序对于等一下的计算优化了太多,可以尝试一下这两种方法的感觉。
接下来就是对于每一块询问里的每一个进行计算了,上面的的过程基本上都是通用的,每个题和每个题不同的地方就在于怎么用O(1)的复杂度求出下一个状态。
CSU 1515 Sequence
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1515
求给定区间里满足|a[i]-a[j]|=1 有多少pair
中南校赛时的一个题,那时不会莫队,然后纵看水题飞走
因为a[i]最大会有2^31所以不能用数组标记,可以用map,事实证明虽然AC 但是很慢
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 #include <map> 6 using namespace std; 7 const int maxn = 100005; 8 typedef long long LL; 9 struct node10 {11 int l,r;12 int id;13 int ans;14 }a[maxn];15 map<int,int>vis;16 int c[maxn];17 int pos[maxn];18 int ans;19 bool cmp(node a,node b)20 {21 if(pos[a.l]==pos[b.l])return a.r<b.r;22 return a.l<b.l;23 }24 bool cmp_id(node a,node b)25 {26 return a.id<b.id;27 }28 void update(int x,int add)29 {30 x = c[x];31 vis[x]+=add;32 ans+=add*vis[x+1];33 if(x>0)ans+=add*vis[x-1];34 35 }36 int main()37 {38 // freopen("in.txt","r",stdin);39 int n,m;40 while(~scanf("%d%d",&n,&m))41 {42 int block = int(sqrt(n));43 vis.clear();44 for(int i = 1;i<=n;++i){scanf("%d",&c[i]);pos[i] = (i-1)/block+1;}45 for(int i = 1;i<=m;++i)46 {47 scanf("%d%d",&a[i].l,&a[i].r);48 a[i].id = i;49 }50 sort(a+1,a+1+m,cmp);51 ans = 0;52 int l = 1,r = 0;53 for(int i = 1;i<=m;++i)54 {55 while(r<a[i].r)update(r+1,1),r++;;56 while(r>a[i].r)update(r,-1),r--;57 while(l<a[i].l)update(l,-1),l++;58 while(l>a[i].l)update(l-1,1),l--;59 a[i].ans = ans;60 }61 sort(a+1,a+1+m,cmp_id);62 for(int i = 1;i<=m;++i)printf("%d\n",a[i].ans);63 }64 return 0;65 }66 67 /**************************************************************68 Problem: 151569 User: round_070 Language: C++71 Result: Accepted72 Time:6328 ms73 Memory:4224 kb74 ****************************************************************/
BZOJ 2038小Z的袜子(hose)
http://www.lydsy.com/JudgeOnline/problem.php?id=2038
这题是经典
1 /************************************************************** 2 Problem: 2038 3 User: round_0 4 Language: C++ 5 Result: Accepted 6 Time:1748 ms 7 Memory:3168 kb 8 ****************************************************************/ 9 10 #include <cstdio>11 #include <cmath>12 #include <algorithm>13 using namespace std;14 const int maxn = 50005;15 typedef long long LL;16 LL sqr(LL x)17 {18 return x*x;19 }20 struct node21 {22 int l;23 int r;24 int id;25 LL a,b;26 }a[maxn];27 int pos[maxn];28 bool cmp(node a,node b)29 {30 if(pos[a.l]==pos[b.l])return a.r<b.r;31 return a.l<b.l;32 }33 bool cmp_id(node a,node b)34 {35 return a.id<b.id;36 }37 LL ans;38 LL cnt[maxn],c[maxn];39 void update(int pos,int add)40 {41 ans-=sqr(cnt[c[pos]]);42 cnt[c[pos]]+=add;43 ans+=sqr(cnt[c[pos]]);44 }45 LL gcd(LL a,LL b)46 {47 return b?gcd(b,a%b):a;48 }49 50 int main()51 {52 // freopen("in.txt","r",stdin);53 int n,m;54 while(~scanf("%d%d",&n,&m))55 {56 int block = (int)sqrt(n);57 for(int i = 1;i<=n;++i)58 {59 scanf("%lld",&c[i]);60 cnt[i] = 0;61 pos[i] = (i-1)/block+1;62 }63 for(int i = 1;i<=m;++i)64 {65 scanf("%d%d",&a[i].l,&a[i].r);66 a[i].id = i;67 }68 ans = 0;69 sort(a+1,a+1+m,cmp);70 int l = 1,r = 0;71 LL x = 0;72 for(int i = 1;i<=m;++i)73 {74 while(r<a[i].r){update(r+1,1);r++;x++;}75 while(r>a[i].r){update(r,-1);r--;x++;}76 while(l<a[i].l){update(l,-1);x++;l++;}77 while(l>a[i].l){update(l-1,1);l--;x++;}78 a[i].a = ans-(r-l+1);79 a[i].b = (LL)(r-l+1)*(r-l);80 LL k = gcd(a[i].a,a[i].b);81 a[i].a/=k;82 a[i].b/=k;83 }84 sort(a+1,a+1+m,cmp_id);85 for(int i = 1;i<=m;++i)printf("%lld/%lld\n",a[i].a,a[i].b);86 }87 return 0;88 }
BZOJ 1878 HH的项链
http://www.lydsy.com/JudgeOnline/problem.php?id=1878
水题
1 /************************************************************** 2 Problem: 1878 3 User: round_0 4 Language: C++ 5 Result: Accepted 6 Time:2908 ms 7 Memory:9416 kb 8 ****************************************************************/ 9 10 #include <cmath>11 #include <cstdio>12 #include <cstring>13 #include <algorithm>14 using namespace std;15 const int maxn = 200005;16 struct node17 {18 int l,r;19 int id;20 int ans;21 }a[maxn];22 int cnt[maxn*5];23 int val[maxn];24 int pos[maxn];25 int ans;26 bool cmp(node a,node b)27 {28 if(pos[a.l]==pos[b.l])return a.r<b.r;29 return a.l<b.l;30 }31 bool cmp_id(node a,node b)32 {33 return a.id<b.id;34 }35 void update(int x,int status)36 {37 x = val[x];38 if(status==1)39 {40 if(!cnt[x])ans++;41 cnt[x]++;42 }43 else44 {45 if(cnt[x]==1)ans--;46 cnt[x]--;47 }48 }49 int main()50 {51 // freopen("in.txt","r",stdin);52 int n,m;53 while(~scanf("%d",&n))54 {55 int block = (int)sqrt(n);56 memset(cnt,0,sizeof(cnt));57 for(int i = 1;i<=n;++i){scanf("%d",&val[i]);pos[i]=(i-1)/block+1;}58 scanf("%d",&m);59 for(int i = 1;i<=m;++i)60 {61 scanf("%d%d",&a[i].l,&a[i].r);62 a[i].id = i;63 }64 sort(a+1,a+1+m,cmp);65 int l = 1,r = 0;66 ans = 0;67 for(int i = 1;i<=m;++i)68 {69 while(r<a[i].r)update(r+1,1),r++;70 while(r>a[i].r)update(r,-1),r--;71 while(l<a[i].l)update(l,-1),l++;72 while(l>a[i].l)update(l-1,1),l--;73 a[i].ans = ans;74 }75 sort(a+1,a+1+m,cmp_id);76 for(int i = 1;i<=m;++i)printf("%d\n",a[i].ans);77 78 }79 return 0;80 }
HDU 4638 Group
http://acm.hdu.edu.cn/showproblem.php?pid=4638
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int maxn = 100005; 7 int c[maxn],pos[maxn]; 8 bool vis[maxn]; 9 struct node10 {11 int l;12 int r;13 int id;14 int ans;15 }a[maxn];16 int ans;17 bool cmp(node a,node b)18 {19 if(pos[a.l]==pos[b.l])return a.r<b.r;20 return a.l<b.l;21 }22 bool cmp_id(node a,node b)23 {24 return a.id<b.id;25 }26 void update(int x,int status)27 {28 int m = c[x],l = m-1,r = m+1;29 if(status==1)30 {31 if(vis[l]==0&&vis[r]==0)ans++;32 else if(vis[l]&&vis[r])ans--;33 vis[m] = 1;34 }35 else36 {37 if(vis[l]==0&&vis[r]==0)ans--;38 else if(vis[l]==1&&vis[r]==1)ans++;39 vis[m] = 0;40 }41 }42 int main()43 {44 // freopen("in.txt","r",stdin);45 int T;scanf("%d",&T);46 while(T--)47 {48 int n,m;scanf("%d%d",&n,&m);49 int block = (int)sqrt(n);50 for(int i = 1;i<=n;++i){scanf("%d",&c[i]);pos[i] = (i-1)/block+1;}51 memset(vis,0,sizeof(vis));52 for(int i = 1;i<=m;++i)53 {54 scanf("%d%d",&a[i].l,&a[i].r);55 a[i].id = i;56 }57 sort(a+1,a+m+1,cmp);58 int l = 1,r = 0;59 ans = 0;60 for(int i = 1;i<=m;++i)61 {62 while(r<a[i].r)update(r+1,1),r++;63 while(r>a[i].r)update(r,-1),r--;64 while(l<a[i].l)update(l,-1),l++;65 while(l>a[i].l)update(l-1,1),l--;66 67 a[i].ans = ans;68 }69 sort(a+1,a+1+m,cmp_id);70 for(int i = 1;i<=m;++i)printf("%d\n",a[i].ans);71 72 }73 return 0;74 }
WHU 1551 Pairs
http://acm.whu.edu.cn/land/problem/detail?problem_id=1551
和CSU1515 本页第一题一样
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 const int maxn = 100005; 7 typedef long long LL; 8 struct node 9 {10 int l,r;11 int id;12 int ans;13 }a[maxn];14 int vis[maxn];15 int c[maxn];16 int pos[maxn];17 int ans;18 bool cmp(node a,node b)19 {20 if(pos[a.l]==pos[b.l])return a.r<b.r;21 return a.l<b.l;22 }23 bool cmp_id(node a,node b)24 {25 return a.id<b.id;26 }27 void update(int x,int add)28 {29 x = c[x];30 for(int i = max(x-2,0);i<=x+2;++i) if(i!=x)31 ans+=add*vis[i];32 if(add==1)ans+=vis[x];33 else ans-=(vis[x]-1);34 vis[x]+=add;35 }36 int main()37 {38 // freopen("in.txt","r",stdin);39 int n,m,kase = 1;40 while(~scanf("%d%d",&n,&m))41 {42 int block = int(sqrt(n));43 memset(vis,0,sizeof(vis));44 for(int i = 1;i<=n;++i){scanf("%d",&c[i]);pos[i] = i/block;}45 for(int i = 1;i<=m;++i)46 {47 scanf("%d%d",&a[i].l,&a[i].r);48 a[i].id = i;49 }50 sort(a+1,a+1+m,cmp);51 ans = 0;52 int l = 1,r = 0;53 for(int i = 1;i<=m;++i)54 {55 while(r<a[i].r)update(r+1,1),r++;;56 while(r>a[i].r)update(r,-1),r--;57 while(l<a[i].l)update(l,-1),l++;58 while(l>a[i].l)update(l-1,1),l--;59 a[i].ans = ans;60 }61 sort(a+1,a+1+m,cmp_id);62 printf("Case %d:\n",kase++);63 for(int i = 1;i<=m;++i)printf("%d\n",a[i].ans);64 }65 return 0;66 }
莫队就先告一段落了,去找点别的好玩的学一下
莫队算法