[bzoj2038][2009国家集训队]小Z的袜子(hose)_莫队
小Z的袜子 hose 2009-国家集训队 bzoj-2038
题目大意:给定一个n个袜子的序列,每个袜子有一个颜色。m次询问:每次询问一段区间中每种颜色袜子个数的平方和。
注释:$1\le n,m\le 5\cdot 10^4$。
想法:
莫队算法的第一道例题。
每次左指针和右指针动的时候注意平方即可,
最后,附上丑陋的代码... ...
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; #define N 80050 struct Node { int s,t,id; int ans; }a[N]; int now; int n,q,block,pos[N],h[N],c[N]; inline bool cmp1(const Node &x,const Node &y) { if(pos[x.s]==pos[y.s]) return x.t<y.t; return pos[x.s]<pos[y.s]; } inline bool cmp2(const Node &x,const Node &y) { return x.id<y.id; } void update(int x,int sig) { if(sig==1) { now+=h[c[x]]; h[c[x]]++; } else { now-=h[c[x]]-1; h[c[x]]--; } /*now-=h[c[x]]; h[c[x]]+=sig; now+=h[c[x]];*/ } void print(int x) { int b=a[x].ans,d=1ll*(a[x].t-a[x].s)*(a[x].t-a[x].s+1)/2; if(b==0) { puts("0/1");return; } int gcd=__gcd(b,d); printf("%d/%d\n",b/gcd,d/gcd); } int main() { scanf("%d%d",&n,&q); int i,l,r=0,j; for(i=1;i<=n;++i) scanf("%d",&c[i]); if(!n)return 0; int size=sqrt(n); block=n/size; for(i=1;i<=block;++i) { l=r+1; r=i*size; for(j=l;j<=r;++j) { pos[j]=i; } } if(r!=n) { l=r+1; r=n; block++; for(i=l;i<=r;++i) { pos[i]=block; } } for(i=1;i<=q;++i)scanf("%d%d",&a[i].s,&a[i].t),a[i].id=i; sort(a+1,a+q+1,cmp1); for(l=1,r=0,i=1;i<=q;++i) { if(a[i].s==a[i].t) { a[i].ans=0; continue; } while(l<a[i].s)update(l,-1),l++; while(l>a[i].s)update(l-1,1),l--; while(r<a[i].t)update(r+1,1),r++; while(r>a[i].t)update(r,-1),r--; a[i].ans=now; } sort(a+1,a+q+1,cmp2); for(i=1;i<=q;i++) { print(i); } }
小结:莫队真可爱/ka
| 欢迎来原网站坐坐! >原文链接<