莫队算法

莫队:

如果你知道了区间l,r的ans。你想知道l-1,r或l,r+1的区间ans,如果你能O(1)转移,就能用莫队在O(n^1.5)(原时间(O(n^2)))解决此为题。(n为个数,m询问数,m和n同级)

首先,讲解一下它的优化原理。

原来有m个询问l和r在这m个询问中跑来跑去,对时间很浪费。于是就对这个询问的序列重新排列。

做法就是:

  • 将n个数分成sqrt(n)块。
  • 按区间排序,以左端点所在块为第一关键字,右端点为第二关键字,进行排序,也就是以(l的分类,r)排列。(来源黄学长的博客

关于时间复杂度:

  • i与i+1在同一块内,r单调递增,所以r是O(n)的。由于有n^0.5块,所以这一部分时间复杂度是n^1.5。
  • i与i+1跨越一块,r最多变化n,由于有n^0.5块,所以这一部分时间复杂度是n^1.5。
  • i与i+1在同一块内时l变化不超过n^0.5,跨越一块也不会超过n^0.5,忽略*2。由于有m次询问(和n同级),所以时间复杂度是n^1.5。(来源黄学长的博客

模板(上模板题BZOJ2038):

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<cstdlib>
 7 #include<vector>
 8 using namespace std;
 9 typedef long long ll;
10 typedef long double ld;
11 typedef pair<int,int> pr;
12 const double pi=acos(-1);
13 #define rep(i,a,n) for(int i=a;i<=n;i++)
14 #define per(i,n,a) for(int i=n;i>=a;i--)
15 #define Rep(i,u) for(int i=head[u];i;i=Next[i])
16 #define clr(a) memset(a,0,sizeof(a))
17 #define pb push_back
18 #define mp make_pair
19 #define fi first
20 #define sc second
21 #define pq priority_queue
22 #define pqb priority_queue <int, vector<int>, less<int> >
23 #define pqs priority_queue <int, vector<int>, greater<int> >
24 #define vec vector
25 ld eps=1e-9;
26 ll pp=1000000007;
27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; }
31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};
32 ll read(){ ll ans=0; char last=' ',ch=getchar();
33 while(ch<'0' || ch>'9')last=ch,ch=getchar();
34 while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
35 if(last=='-')ans=-ans; return ans;
36 }
37 int pos[50005],s[50005],c[50005];
38 ll ans;
39 inline ll sqr(ll x){
40     return x*x;
41 } 
42 inline ll gcd(ll a,ll b){
43     return b==0?a:gcd(b,a%b);
44 }
45 struct node{
46     int l,r,id; ll a,b;
47 }a[50005];
48 int cmp(node a,node b){
49     return (pos[a.l]<pos[b.l]||pos[a.l]==pos[b.l]&&a.r<b.r);
50 }
51 int cmp_(node a,node b){
52     return (a.id<b.id);
53 }
54 void Update(int x,int v){
55     ans-=sqr(s[c[x]]); s[c[x]]+=v; ans+=sqr(s[c[x]]);
56 }
57 int main()
58 {
59     int n=read(),m=read();
60     for (int i=1;i<=n;i++) c[i]=read();
61     for (int i=1;i<=m;i++) a[i].l=read(),a[i].r=read(),a[i].id=i;
62     int block=(int)sqrt(n);
63     for (int i=1;i<=n;i++)
64       pos[i]=(i-1)/block+1;
65     sort(a+1,a+m+1,cmp);
66     for (int i=1,l=1,r=0;i<=m;i++){
67         for (;r<a[i].r;r++) Update(r+1,1);
68         for (;r>a[i].r;r--) Update(r,-1);
69         for (;l<a[i].l;l++) Update(l,-1);
70         for (;l>a[i].l;l--) Update(l-1,1);
71         if (a[i].l==a[i].r){
72             a[i].a=0; a[i].b=0;
73             continue;
74         }
75         a[i].a=ans-(a[i].r-a[i].l+1);
76         a[i].b=(ll)(a[i].r-a[i].l+1)*(a[i].r-a[i].l);
77         ll k=gcd(a[i].a,a[i].b);
78         a[i].a/=k; a[i].b/=k;
79     }
80     sort(a+1,a+m+1,cmp_);
81     for (int i=1;i<=m;i++){
82         printf("%lld/%lld
",a[i].a,a[i].b);
83     }
84     return 0;
85  } 
View Code
原文地址:https://www.cnblogs.com/SXia/p/6776429.html