BZOJ 2038: [2009国家集训队]小Z的袜子(hose)&&莫队算法
这里跟曼哈顿最小生成树没有太大的关系。
时间复杂度证明:
【BZOJ2038 小Z的袜子 AC代码】
排序方式:
第一关键字:l所在的块;
第二关键字:r从小到大。
2017-04-06
#include<cmath> #include<cstdio> #include<algorithm> using namespace std; const int N=2e5+5; typedef long long ll; struct block{int l,r,id;}Q[N]; int n,m,bsize,a[N],f[N]; ll nowans,gg,ans1[N],ans2[N]; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } bool operator <(const block &a,const block &b){ return a.l/bsize!=b.l/bsize?a.l/bsize<b.l/bsize:a.r<b.r; } inline void ins(int x){ nowans+=f[x]++; } inline void del(int x){ nowans-=--f[x]; } int main(){ n=read();m=read();bsize=sqrt(n+0.5); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=m;i++) Q[i].l=read(),Q[i].r=read(),Q[i].id=i; sort(Q+1,Q+m+1); int l=1,r=0; for(int i=1;i<=m;i++){ while(l>Q[i].l) ins(a[--l]); while(l<Q[i].l) del(a[l++]); while(r<Q[i].r) ins(a[++r]); while(r>Q[i].r) del(a[r--]); ans1[Q[i].id]=nowans; ans2[Q[i].id]=1LL*(r-l+1)*(r-l)/2; } for(int i=1;i<=m;i++){ if(ans1[i]) gg=__gcd(ans1[i],ans2[i]),printf("%lld/%lld\n",ans1[i]/gg,ans2[i]/gg); else puts("0/1"); } return 0; }
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int N=2e5+7; struct node{ int l,r,t,pos; bool operator < (const node &a)const{ return pos==a.pos?r<a.r:pos<a.pos; } }b[N]; int n,m,l,r,a[N],f[N]; ll res,ans1[N],ans2[N]; ll gcd(ll a,ll b){ if(!b) return a; return gcd(b,a%b); } int main(){ //freopen("hose.in","r",stdin); //freopen("hose.out","w",stdout); n=read();m=read(); for(int i=1;i<=n;i++) a[i]=read(); int k=sqrt(n*1.0)+0.5; for(int i=1;i<=m;i++){ b[i].l=read();b[i].r=read(); b[i].t=i;b[i].pos=b[i].l/k; } sort(b+1,b+m+1); memset(f,0,sizeof f); l=1;r=0;res=0; for(int i=1;i<=m;i++){ while(r>b[i].r){ res-=(ll)f[a[r]]-1; f[a[r]]--; r--; } while(r<b[i].r){ r++; f[a[r]]++; res+=(ll)f[a[r]]-1; } while(l>b[i].l){ l--; f[a[l]]++; res+=(ll)f[a[l]]-1; } while(l<b[i].l){ res-=(ll)f[a[l]]-1; f[a[l]]--; l++; } ans1[b[i].t]=res; ans2[b[i].t]=(ll)(r-l+1)*(r-l)/2; } for(int i=1;i<=m;i++){ if(!ans1[i]){ puts("0/1"); continue; } ll gg=gcd(ans1[i],ans2[i]); printf("%lld/%lld\n",ans1[i]/gg,ans2[i]/gg); //printf("%I64d/%I64d\n",ans1[i]/gg,ans2[i]/gg); } return 0; }
reference: