HDU 4777 離線樹狀陣列 + 思維
阿新 • • 發佈:2018-11-19
/** HDU 4777 離線樹狀陣列 + 思維 連結:http://acm.hdu.edu.cn/showproblem.php?pid=4777 題意:區間不與其它數字互質的數的個數; 分析:可先求解互質的數的個數 再用區間長度減去即可; 維護陣列l[i],r[i] : 第i個位置上的數 與左端數互質的數的最近位置 與右端數互質的數的最近位置; Get l[i] r[i]:對當前數進行質因數分解,直接進行更新即可; 離線處理區間,用類似於莫隊的思想,對所給區間按照右端點進行排序; 不斷的向右進行擴充套件,對於當前區間,L + 1 對於列舉的 k L+1 R -1; 樹狀陣列區間更新進行求和即可; ***************時間複雜度&&tricks***************** nlogn 質因數的儲存還是暴力的好..... */ #include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=2e5+7; int n,q; struct node{ int l,r,id; }op[maxn]; bool cmp(node a,node b){ return a.r<b.r; } int c[maxn]; int lowbit(int x){return x&(-x);} void add(int x,int val){ if(x==0) return ; while(x<=n) { c[x]+=val; x+=lowbit(x); } } int sum(int x){ int ans=0; while(x){ ans+=c[x]; x-=lowbit(x); } return ans; } int prime[maxn],cnt=0,np[maxn]; int l[maxn],r[maxn],val[maxn]; vector<int>fac[maxn]; void getprime(){ memset(prime,0,sizeof(prime)); for(int i=2;i<maxn;i++){ if(!prime[i]) prime[++cnt]=i; for(int j=1;j<=cnt;j++){ if(i*prime[j]>=maxn) break; prime[i*prime[j]]=1; if(i%prime[j]==0) break; } } for(int i=2;i<maxn;i++){ int x=i; for(int j=1;j<=cnt&&prime[j]*prime[j]<=x;j++){ if(x%prime[j]==0) { while(x%prime[j]==0) x/=prime[j]; fac[i].push_back(prime[j]); } } if(x>1) fac[i].push_back(x); } } vector<int>vec[maxn]; int a[maxn],tmp[maxn]; int main (){ getprime(); while(~scanf("%d %d",&n,&q)){ if(n==0&&q==0) break; for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=q;i++) scanf("%d %d",&op[i].l,&op[i].r),op[i].id=i; memset(tmp,0,sizeof(tmp)); for(int i=0;i<maxn;i++) l[i]=0; for(int i=1;i<=n;i++){ int sz=fac[a[i]].size(); for(int j=0;j<sz;j++){ l[i]=max(l[i],tmp[fac[a[i]][j]]); tmp[fac[a[i]][j]]=i; } } for(int i=0;i<maxn;i++) tmp[i]=n+1,r[i]=n+1; for(int i=n;i>=1;i--){ int sz=fac[a[i]].size(); for(int j=0;j<sz;j++){ r[i]=min(r[i],tmp[fac[a[i]][j]]); tmp[fac[a[i]][j]]=i; } } for(int i=0;i<=n+2;i++) vec[i].clear(); for(int i=1;i<=n;i++) vec[r[i]].push_back(i); sort(op+1,op+1+q,cmp); memset(c,0,sizeof(c)); for(int i=1,k=1;i<=q;i++){ while(k<=n&&k<=op[i].r){ add(l[k],1); for(int o=0;o<vec[k].size();o++){ int v=vec[k][o]; add(v,1); add(l[v],-1); } k++; } val[op[i].id]=op[i].r-op[i].l+1-(sum(op[i].r)-sum(op[i].l-1)); } for(int i=1;i<=q;i++) printf("%d\n",val[i]); } return 0; }