HDU 4777 Rabbit Kingdom(树状数组离线处理)
分析:对每个数预处理,求出与a[i]不互素的左右两边最远的位置l[i]和r[i],则l[i],r[i]中就是与a[i]都不互素的左右两端的第一个数的位置.
接下来我们将维护一个A[i]树状数组,使得sum(R)-sum(L-1)就是我们所求的区间[L,R]的答案.
首先我们将所有区间查询读入,然后按L从小到大排序.
第一步:我们把所有l[i]<1(即这个a[i]左边全是和它互素的数)的i位置加1,然后在r[i](要求r[i]<=n)位置减1,即add(i,1),add(r[i],-1).注意这里在i位置上的值是a[i]是否独立的主导,而在r[i]上的值是a[i]是否独立的辅助,当a[r[i]]作为主导的时候,另外考虑即可.---查询结果前的预处理操作
做完这步,我们保证对所有区间[1,R](R<=n可以任意,但是区间起点必须是1)的查询结果就是:sum(R)-sum(0).(自己分l[i]<1和l[i]>=1两种情况验证一下,看看是不是这样)-----------------------查询结果
第二步:我们将对区间[2,R]求结果,因为之前已经求出了[1,R]的结果就是sum(R)-sum(0),所以我们现在求[2,R]区间的查询结果需要消除a[1]对区间[2,R]的影响.因为a[1]的r[1]肯定在1后面,之前第一步我们执行了add(i,1),add(r[i],-1)操作,所以现在我们需要还原,所以执行:
add(i,-1)和add(r[i],1).--------------------------------查询结果后的清除操作
执行完这两个操作就等于是a[1]永久的从a[n]数组内消失了,我们现在是计算[2,R]区间的,我们也可以认为2就是a[n]数组的起点,a[1]从来没有存在过.所以以a[2]作为数组新的起点的话,现在又有两类a[i]需要处理,第一类是l[i]==1的,另一个类是l[i]>1的.
l[i]>1的不用管,因为我们现在求的是区间[2,R](其实这类似于我们第一步处理区间[1,R]的时候对于l[i]>=1的a[i]不处理一样,自己思考一下是不是?)
对于l[i]==1的a[i],那么就需要执行操作add(i,1)和add(r[i],-1)(要求r[i]<=n),执行完了这一步我们保证对于区间[2,R]的任意查询结果就是:
sum(R)-sum(1)
需要用一个vector来保存vec[ l[i] ]=I,来执行查询结果前的预处理操作.
接下来以此类推即可.
然后来说说我们如何求出所有a[i]的l[i]和r[i]呢?下面只说r[i]的求法,l[i]的求法类似.:
首先我们定义一个数组d[MAXN]=n+1,其中d[x]=n+1表示含有因子x的第一个a[i]在n+1位置.然后我们从第n个数开始扫描,在扫描a[n]之前我们还没有得到任何一个因子,所以所有的d[x]都是=n+1.然后我们对a[n]质因数分解,得到了它所有的素因子y,此时我们就可以令d[y]=n了.然后我们又用d[y]的值去更新n-1的r[n-1]值.以此类推.
AC代码:1890ms
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int MAXN=200000+100; int prime[MAXN+1]; int getPrime()//得到小于等于MAXN的所有素数,prime[0]存放的是个数 { memset(prime,0,sizeof(prime));//prime[0]计数,prime[i]既用来表示第i个素数,又用来表示是否被访问 for(int i=2; i<=MAXN; i++) { if(!prime[i]) prime[++prime[0]]=i; for(int j=1; j<=prime[0]&&prime[j]<=MAXN/i; j++) { prime[prime[j]*i]=1; if(i%prime[j]==0) break; } } return prime[0]; } long long factor[100][2]; int facCnt; int getFactors(long long x) { //把x进行素数分解,分解成360=2^3*3^2*5^1。 //factor[i][0]为第i+1个素因子的值,factor[i][1]为第i+1个素因子的幂 facCnt=0; long long tmp=x; for(int i=1; prime[i]<=tmp/prime[i]; i++)//tmp至少为当前素数的平方才继续 { factor[facCnt][1]=0; if(tmp%prime[i]==0) { factor[facCnt][0]=prime[i]; while(tmp%prime[i]==0) { factor[facCnt][1]++; tmp/=prime[i]; } facCnt++; } } if(tmp!=1) { factor[facCnt][0]=tmp; factor[facCnt++][1]=1; } return facCnt; } int c[MAXN+1]; int lowbit(int x){return x&(-x);} int sum(int x) { int res=0; while(x) { res += c[x]; x-=lowbit(x); } return res; } void add(int x,int v) { while(x<=MAXN) { c[x] +=v; x +=lowbit(x); } } struct node { int l,r; int index; bool operator <(const node &b)const { return l<b.l; } }nodes[MAXN];//存查询命令 int ans[MAXN];//存查询结果 int a[MAXN];//存初始n个数据 int b[MAXN];//b[i]表示含有因子i的第一个数的位置 int l[MAXN],r[MAXN];//与a[i]的值不互素的左边第一个数是a[l[i]],右边第一个数是a[r[i]] vector<int> vec[MAXN]; int pp[MAXN][20];//pp[i][0]=x表示a[i]有x个素因子,pp[i][j]表示a[i]的第j个素因子 int main() { getPrime();//记得要先算素数,才可以支持后面的素因子分解 int n,m; while(scanf("%d%d",&n,&m)==2&&n&&m) { for(int i=0;i<=n+1;i++)vec[i].clear(); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=1;i<=m;i++) { scanf("%d%d",&nodes[i].l,&nodes[i].r); nodes[i].index=i; } sort(nodes+1,nodes+m+1); for(int i=2;i<MAXN;i++)b[i]=n+1;//含有因子i的数 最早出现的位置 for(int i=n;i>=1;i--) { pp[i][0]=getFactors(a[i]);//pp用来加速后面对l[i]的处理 int pos=n+1; for(int j=0;j<facCnt;j++) { pos = min(pos,b[factor[j][0]]); b[factor[j][0]]=i; pp[i][j+1]= factor[j][0]; } r[i]=pos; } for(int i=2;i<MAXN;i++)b[i]=0;//含有因子i的数 最早出现的位置 for(int i=1;i<=n;i++) { //getFactors(a[i]); int pos=0; facCnt= pp[i][0]; for(int j=0;j<facCnt;j++) { factor[j][0] = pp[i][j+1]; pos = max(pos,b[factor[j][0]]); b[factor[j][0]]=i; } l[i]=pos; vec[l[i]].push_back(i); } memset(ans,0,sizeof(ans)); memset(c,0,sizeof(c)); int p=1;//指针,指向当前处理到第几个查询 for(int i=1;i<=n;i++)//当前处理第i个元素 { if(p>m) break; for(unsigned int k=0;k<vec[i-1].size();k++) { int x=vec[i-1][k];//l[x]=i-1,所以需要处理 add(x,1); add(r[x],-1); }//这步处理完,我们保证[i,R]区间的答案是sum(R)-sum(i-1) while(p<=m&&nodes[p].l==i) { ans[nodes[p].index]= sum(nodes[p].r)-sum(nodes[p].l-1); p++; }//这步是完成[i,R]的所有查询 add(i,-1);//永久清除a[i]及其带来的影响,从i+1开始(从新开始),等于序列中从来没有过a[i] add(r[i],1); } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); } return 0; }