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

莫队算法

时间:2015-02-01 19:06:12      阅读:480      评论:0      收藏:0      [点我收藏+]

标签:

  特意学了一下莫队算法,做了几个题,总结一下。

  目前还只是学了线性序列的莫队的分块,没有学什么曼哈顿最小生成树。分开的写法也挺简单粗暴明了(据说曼哈顿距离的最小生成树并不好写)

时间复杂度是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 node
10 {
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: 1515
69     User: round_0
70     Language: C++
71     Result: Accepted
72     Time:6328 ms
73     Memory:4224 kb
74 ****************************************************************/

  

    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 node
21 {
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 node
17 {
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     else
44     {
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 node
10 {
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     else
36     {
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 }

    莫队就先告一段落了,去找点别的好玩的学一下

莫队算法

标签:

原文地址:http://www.cnblogs.com/GJKACAC/p/4265836.html

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