莫队算法
特意学了一下莫队算法,做了几个题,总结一下。
目前还只是学了线性序列的莫队的分块,没有学什么曼哈顿最小生成树。分开的写法也挺简单粗暴明了(据说曼哈顿距离的最小生成树并不好写)
时间复杂度是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 }
莫队就先告一段落了,去找点别的好玩的学一下