1. 程式人生 > >HDU 4777 離線樹狀陣列 + 思維

HDU 4777 離線樹狀陣列 + 思維

/**
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;
}