bzoj 2906颜色
Posted kgxw0430
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 2906颜色相关的知识,希望对你有一定的参考价值。
这道题起初看错题意,询问的是在区间L,R内在l,r内的每个数值出现次数的平方的和,没注意到平方,就想到了一个带前缀和的思路。假如原本分T块,其实我们只需要预处理T个前缀就好了,每一个前缀,单独处理一个数组,再保存一个关于权值出现次数的前缀,每次查询L,R,进行分块,一个连续的块的答案可以通过前缀求得,两边多余的只需要扫一遍就好了。还写了个代码哈哈。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int N=5e4+10; const int M=2e4+10; int t,s,n,m,Q,p,q,pos,lan,a[N],sum[350][M]; int ask(int l,int r,int L,int R){ //l=l^lan,r=r^lan,L=L^lan,R=R^lan; if(l>r) swap(l,r); if(L>R) swap(L,R); p=l/s,q=r/s; if(p%s==1) p++; else if(p%s) p+=2; else p++; if(q-p<0){ int ans=0; for(int i=l;i<=r;++i) if(a[i]>=L&&a[i]<=R) ans++; return ans; }else{ int ans=0; ans=sum[q][R]-sum[q][L-1]-sum[p-1][R]+sum[p-1][L-1]; for(int i=l;i<=(p-1)*s;++i) if(a[i]>=L&&a[i]<=R) ans++; for(int i=q*s+1;i<=r;++i) if(a[i]>=L&&a[i]<=R) ans++; return ans; } } int main(){ scanf("%d%d%d",&n,&m,&Q); for(int i=1;i<=n;++i) scanf("%d",&a[i]); t=sqrt(1.0*Q*n/m);s=n/t; for(int i=1;i<=t;++i){ for(int j=1;j<=s*i;++j) sum[i][a[j]]++; } for(int i=1;i<=t;++i){ for(int j=1;j<=m;++j) sum[i][j]+=sum[i][j-1]; } for(int i=1;i<=Q;++i){ int l,r,L,R;scanf("%d%d%d%d",&l,&r,&L,&R); printf("%d ",lan=ask(l,r,L,R)); } return 0; }
然而真实题意是还需要平方,所以不能这么写。那么可以有这么一种写法,我们像蒲公英那道题一样,对于每个块来说,还是存储在这个块内每个数出现的次数,并且存一个块的答案。两边多余的扫一遍更新答案就行了。关键在于怎么更新答案,其实一个平方把它拆开不就好了,假设当前某个值出现次数为x,你已经求了它的平方,这时候又出现了一次,你只需要加上1+2x就行了。复杂度和蒲公英是一样的,那么此题就做完了。
以上是关于bzoj 2906颜色的主要内容,如果未能解决你的问题,请参考以下文章
c_cpp UV Index Indicator订阅PubNub并使用颜色显示UV索引值。博文的代码片段。在这里查看项目:https:/