BZOJ 2038: [2009国家集训队]小Z的袜子(hose)(莫队算法)
http://www.lydsy.com/JudgeOnline/problem.php?id=2038
题意:
思路:
简单介绍一下莫队算法,使用这个算法需要满足一些条件:
①区间不修改
②离线处理
③在知道了[l,r]的答案后,在此基础上能在比较快地在O(1)得到相邻区间[l+1,r]、[l-1,r]、[l,r-1]、[l,r+1]的答案
处理过程:
- 首先对原序列进行分块,√n块每块√n个;
- 然后对所有查询的区间[l,r]进行排序,首先按l所在的块序号升序排序,如果一样就按r升序排序;
- 之后就一些加加减减
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 #include<cmath> 9 #include<map> 10 #include<set> 11 using namespace std; 12 typedef long long ll; 13 typedef pair<int,int> pll; 14 const int INF = 0x3f3f3f3f; 15 const int maxn=50000+5; 16 17 int n,m,unit; 18 ll tmp,num[maxn]; 19 int a[maxn]; 20 21 struct node 22 { 23 int l,r,id; 24 }query[maxn]; 25 26 ll gcd(ll a,ll b) 27 { 28 return b==0?a:(gcd(b,a%b)); 29 } 30 31 struct Node 32 { 33 ll a,b; 34 void reduce() 35 { 36 ll g=gcd(a,b); 37 a/=g; 38 b/=g; 39 } 40 }ans[maxn]; 41 42 bool cmp(node a, node b) 43 { 44 if(a.l/unit != b.l/unit) return a.l/unit<b.l/unit; 45 else return a.r<b.r; 46 } 47 48 void update(int x, int d) 49 { 50 tmp-=num[a[x]]*num[a[x]]; 51 num[a[x]]+=d; 52 tmp+=num[a[x]]*num[a[x]]; 53 } 54 55 int main() 56 { 57 //freopen("in.txt","r",stdin); 58 scanf("%d%d",&n,&m); 59 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 60 for(int i=1;i<=m;i++) 61 { 62 scanf("%d%d",&query[i].l,&query[i].r); 63 query[i].id=i; 64 } 65 unit=(int)sqrt(n); 66 sort(query+1,query+m+1,cmp); 67 tmp=0; 68 memset(num,0,sizeof(num)); 69 int l=1,r=0; 70 for(int i=1;i<=m;i++) 71 { 72 while(r<query[i].r) r++,update(r,1); 73 while(r>query[i].r) update(r,-1),r--; 74 while(l<query[i].l) update(l,-1),l++; 75 while(l>query[i].l) l--,update(l,1); 76 ans[query[i].id].a=tmp-(r-l+1); 77 ans[query[i].id].b=(ll)(r-l+1)*(r-l); 78 ans[query[i].id].reduce(); 79 } 80 for(int i=1;i<=m;i++) 81 { 82 printf("%lld/%lld\n",ans[i].a,ans[i].b); 83 } 84 return 0; 85 }