hdu 4777 Rabbit Kingdom 区间覆盖

//	hdu 4777 Rabbit Kingdom 区间覆盖
//
//	题目大意:
//
//		给n个数,有q个区间查询,求出[L,R]区间内有多少个互质的数
//
//	解题思路:
//
//		首先我们将问题转化,互质个数 = 总的个数 - 不互质的个数.
//	对于每个数,我们求一个L[i],R[i]表示分别到左右最近的与i不互质的
//	的数的位置.这个用扫描的方式,记录一下一个数因子出现的位置即可.
//	对于一个区间[L,R].我们对L[i],R[i]进行讨论.如果L[i]或者R[i]在当前
//	区间中,那么这个数一定是不合法的所以去掉这一个数.但是当L[i]和R[i]
//	同时出现在所要查询的区间中,我们在上一步多减了1.所以要把它加回来
//	处理单边界的情况可以将区间分成[L[i],i] 和 [i,R[i]].对于每个询问
//	进行离线处理.用树状数组求值.将区间按照右边界升序排列,对于区间查询
//	转换成f(r) - f(s - 1)的形式
//
//	感悟:
//
//		这道题,是我遇到的第一个区间覆盖的题目,哎,还是太弱了,什么都不会.
//	刚开始还理解了半天呢.不过现在看来还是挺好理解的.继续加油吧~~~FIGHTING!!!

#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#define For(x,a,b,c) for (int x = a; x <= b; x += c)
#define Ffor(x,a,b,c) for (int x = a; x >= b; x -= c)
#define cls(x,a) memset(x,a,sizeof(x))
using namespace std;
typedef long long ll;

const double PI = acos(-1.0);
const double EPS = 1e-10;
const int MAX_N = 2e5 + 8;
const double INF = 1e9;
int N,M;

int a[MAX_N];
bool isp[MAX_N];
int pri[MAX_N];
int L[MAX_N];
int R[MAX_N];
int cnt ;
int MX;
int pos[MAX_N];

vector<int> g[MAX_N];

struct ques{
	int l;
	int r;
	int id;

	ques(){

	}
	ques(int l,int r,int id):l(l),r(r),id(id){

	}

	bool operator < (const ques& o) const{
		return r < o.r;
	}

}q[MAX_N],line[3][MAX_N];

struct BIT{
	int sum[MAX_N];

	void init(){
		cls(sum,0);
	}

	int lowbit(int x){
		return x & -x;
	}

	void add(int x,int d){
		if (x == 0 || x == N + 1)
			return ;

		while(x <= N){
			sum[x] += d;
			x += lowbit(x);
		}
	}

	int query(int x){
		int res = 0 ;
		while(x >= 1){
			res += sum[x];
			x -= lowbit(x);
		}
		return res;
	}

}bit;

void init(){
	cnt = 0;
	isp[0] = isp[1] = 1;
	for (int i = 2 ;i < MAX_N;i ++){
		if (!isp[i]){
			pri[cnt++] = i;
			for (ll j = (ll)i * i ; j < MAX_N; j +=i)
				isp[j] = 1;
		}
	}

}


void get(){
	cls(pos,0);
	for (int i = 1 ;i <= N; i++){
		int p = 0;
		for (int j = 0 ; j < g[i].size();j ++){
			p = max(p,pos[g[i][j]]);
			pos[g[i][j]] = i;
		}
		L[i] = p;
	}

	for (int i = 1;i <= MX; i ++)
		pos[i] = N + 1;

	for (int i = N; i >= 1;i --){
		int p = N + 1;
		for (int j = 0; j < g[i].size();j ++){
			p = min(p,pos[g[i][j]]);
			pos[g[i][j]] = i;
		}
		R[i] = p;
	}

}


int ans[3][MAX_N];

void getans(int id){
	sort(line[id] + 1, line[id] + N + 1);

	bit.init();

	int j = 1;
	for (int i = 1;i <= M; i++){
		int l = q[i].l;
		int r = q[i].r;
		int idx = q[i].id;

		while(j <= N && line[id][j].r <= r){
			bit.add(line[id][j].l,1);
			j++;
		}
		ans[id][idx] = bit.query(r) - bit.query(l - 1);
	}


}
int sum[MAX_N];
void print(){
	for (int i = 1;i <= N;i ++){
		printf("%d %d\n",L[i],R[i]);
	}
}

void getPos(){
	for (int i  = 1;i <= MX;i ++)
		pos[i] = 0;

	for (int i = 1 ;i <= N;i ++){
		int tmp = a[i];
		int p = 0;
		for (int j = 2;j * j <= tmp ; j++){
			if (tmp % j)	continue;
			p = max(p,pos[j]);
			pos[j] = i;
			while(tmp % j == 0)
				tmp /= j;
		}

		if (tmp > 1){
			p = max(p,pos[tmp]);
			pos[tmp] = i;
		}
		L[i] = p;
	}

	for (int i = MX ;i >=0 ; i--){
		pos[i] = N + 1;
	}

	for (int i = N ; i >= 1 ; i --){
		int tmp = a[i];
		int p = N + 1;
		for (int j = 2;j * j <= tmp ; j++){
			if (tmp % j)	continue;
			p = min(p,pos[j]);
			pos[j] = i;
			while(tmp%j == 0) tmp /= j;
		}
		if (tmp > 1){
			p = min(p,pos[tmp]);
			pos[tmp] = i;
		}
		R[i] = p;
	}


}

void print1(){
	for (int i = 1;i <= N;i ++){
		for (int j = 0 ;j < g[i].size();j ++)
			printf("%d ",g[i][j]);
		puts("");
	}
}

void input(){
	MX = 0;
	for (int i = 1; i<= N;i ++){
		scanf("%d",&a[i]);
		MX = max(MX,a[i]);
	}

	for (int i = 1; i <= N;i ++)
		g[i].clear();

	for (int i = 1;i <= N;i ++){ // 这种求法MLE
		g[i].resize(7);
		int x = a[i];
		int c = 0;
		for (int j = 0 ; j < cnt && pri[x] ;j ++){
			if (x % pri[j] == 0){
				g[i][c++] = pri[j];
				
				while(x % pri[j] == 0){
					x /= pri[j];
				}
			}
		}
		if (x > 1)
			g[i][c++] = x;
		g[i].resize(c);
	}
	
	//print1();

	//get();
	
	getPos();

	//print();

	for (int i = 1;i <= M; i ++){
		int u,v;
		scanf("%d%d",&u,&v);

		q[i] = ques(u,v,i);
		sum[i] = v - u + 1;

	}

	sort(q+1,q+M+1);
	

	for (int i = 1;i <= N; i++){
		line[0][i] = ques(L[i],i,0);
		line[1][i] = ques(i,R[i],0);
		line[2][i] = ques(L[i],R[i],0);
	}
	
	getans(0);
	getans(1);
	getans(2);

	for (int i = 1;i <= M ;i ++){
		printf("%d\n",sum[i] - ans[0][i] - ans[1][i] + ans[2][i]);
	}


}

int main(){

	init();
	//freopen("1.in","r",stdin);
	while(scanf("%d%d",&N,&M)!=EOF){
		input();
	}
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值