莫队算法
莫队:
如果你知道了区间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\n",a[i].a,a[i].b); 83 } 84 return 0; 85 }