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 }

 

posted @ 2017-08-29 07:56  Kayden_Cheung  阅读(179)  评论(0编辑  收藏  举报
//目录