【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 }