【bzoj2038】[2009国家集训队]小Z的袜子(hose)

来源:互联网 发布:unity3d如何设置中文 编辑:程序博客网 时间:2024/06/11 20:06

题目链接

第一次写莫队算法的题

如果我们已知[l,r]的答案,能在O(1)时间得到[l+1,r]的答案以及[l,r-1]的答案,即可使用莫队算法。时间复杂度为O(n^1.5)。如果只能在logn的时间移动区间,则时间复杂度是O(n^1.5*log n)。

所以,一道莫队的题,就想想怎么得到移动左端点或者右端点得到的新的答案就好了

这题显然可以O(1)作转移

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<cmath>#define For(i,j,k) for(int i=j;i<=k;i++)#define Forr(i,j,k) for(int i=j;i>=k;i--)#define ll long longusing namespace std;const int N=50000+5;struct node{int l,r,id;ll a,b;}a[N];inline int read(){char c=getchar();while(c<'0'||c>'9')c=getchar();int x=c-'0';c=getchar();while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}return x;}int n,m,block,belong[N],c[N],s[N];int compare(const node w1,const node w2){if(belong[w1.l]==belong[w2.l])return w1.r<w2.r;return w1.l<w2.l;}int compare2(const node w1,const node w2){return w1.id<w2.id;}ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}ll ans;void update1(int k){ans+=s[c[k]];s[c[k]]++;}void update2(int k){ans-=s[c[k]]-1;s[c[k]]--;}void solve(){int l=1,r=0;For(i,1,m){if(a[i].l==a[i].r){a[i].a=0;a[i].b=1;continue;}while(l<a[i].l){update2(l);l++;}while(l>a[i].l){l--;update1(l);}while(r<a[i].r){r++;update1(r);}while(r>a[i].r){update2(r);r--;}a[i].a=ans;if(a[i].a==0){a[i].b=1;continue;}a[i].b=(ll)(a[i].r-a[i].l+1)*(a[i].r-a[i].l)/2;ll k=gcd(a[i].a,a[i].b);a[i].a/=k;a[i].b/=k;}}int main(){n=read();m=read();block=int(sqrt(n));For(i,1,n)belong[i]=(i-1)/block+1;For(i,1,n)c[i]=read();For(i,1,m){a[i].l=read();a[i].r=read();a[i].id=i;}sort(a+1,a+m+1,compare);solve();sort(a+1,a+m+1,compare2);For(i,1,m)printf("%lld/%lld\n",a[i].a,a[i].b);return 0;}