【bzoj2038-小z的袜子】莫队算法

莫队例题。

莫队学习:https://www.cnblogs.com/Paul-Guderian/p/6933799.html

本题 分子是sigma(c(sum[a[i]],2)),分母是sigma(l-r+1,2); 维护分子和即可。

莫队适用范围:离线,区间,区间转移到下一格O(1)。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<cmath>
 7 using namespace std;
 8 
 9 const int N=50010;
10 typedef long long LL;
11 int n,m,sq,a[N];
12 LL ans,gcd,sum[N];
13 struct node{
14     int l,r,k,id;
15     LL fz,fm;
16 };
17 node b[N];
18 
19 int maxx(int x,int y){return x>y?x:y;}
20 bool cmp1(node x,node y)
21 {
22     if(x.k==y.k) return x.r<y.r;
23     return x.l<y.l;
24 }
25 bool cmp2(node x,node y)
26 {
27     return x.id<y.id;
28 }
29 void revise(int x,int d)
30 {
31     ans-=sum[a[x]]*(sum[a[x]]-1)/2;
32     sum[a[x]]+=d;
33     ans+=sum[a[x]]*(sum[a[x]]-1)/2;
34 }
35 LL getgcd(LL a,LL b)
36 {
37     return b?getgcd(b,a%b):a;
38 }
39 
40 int main()
41 {
42     freopen("a.in","r",stdin);
43     freopen("a.out","w",stdout);
44     scanf("%d%d",&n,&m);sq=sqrt(n);
45     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
46     for(int i=1;i<=m;i++)
47     {
48         scanf("%d%d",&b[i].l,&b[i].r);
49         b[i].k=b[i].l/sq;
50         b[i].id=i;
51     }
52     sort(b+1,b+m+1,cmp1);
53     memset(sum,0,sizeof(sum));
54     int l=1,r=1;sum[a[1]]=1;ans=0;
55     for(int i=1;i<=m;i++)
56     {
57         while(l<b[i].l) {revise(l,-1);l++;}
58         while(l>b[i].l) {revise(l-1,1);l--;}
59         while(r<b[i].r) {revise(r+1,1);r++;}
60         while(r>b[i].r) {revise(r,-1);r--;}
61         b[i].fz=ans;b[i].fm=((LL)(b[i].r-b[i].l+1))*((LL)(b[i].r-b[i].l))/2;
62         gcd=getgcd(b[i].fz,b[i].fm);
63         b[i].fz/=gcd;b[i].fm/=gcd;
64         if(b[i].fz==0) b[i].fm=1;
65     }
66     sort(b+1,b+m+1,cmp2);
67     for(int i=1;i<=m;i++)
68     {
69         printf("%lld/%lld\n",b[i].fz,b[i].fm);
70     }
71     return 0;
72 }

 

posted @ 2018-07-19 23:31  拦路雨偏似雪花  阅读(201)  评论(0编辑  收藏  举报