题意:
给出m个区间查询,查询 区间里和区间中的其他数字 都互质 的数字的个数
思路:
简单题,因为并没有 修改,全是查询
把所有查询读入,按照左端点 从左往右来处理。(原因稍后
首先预处理对于每一个位置(id)的数字,往左和往右最远到哪个位置,会出现和这个数字不互质的数字,用l[id]和r[id]保存下来。同时用邻接表(因为这么处理比较简单)保存下来对于一个位置iid,有哪个数字,它的“不互质区间”左端点是iid。——其实我感觉这个预处理过程,用到了素数打表,整数质分界,和我以前不知道的处理方法,比主算法还要难...sigh
然后就是用树状数组处理了。我们从数组最左端开始,每处理到一个位置id,这个位置右边的所有数字,就不用再考虑当前这个数字的影响了。所以我们就可以把所有L[x]=id的位置x 的count + 1,然后R[x]的count - 1。 同时我们应该把R[id]的count+1(因为我们之前给x的count+1的时候,曾经把R[x]的count减成了-1)
我也知道我写的不好理解...但是就是很明确却不大容易想到...:)
你来想,对于按照左端点从小到大排完序的所有区间,每次处理到区间左端点左边的那个位置时,当前区间和就是答案!真是好~
code:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#include<cstdlib>
using namespace std;
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))
#define mod 1000000007
typedef pair<int,int> pii;
typedef long long LL;
//------------------------------
const int maxn = 200005;
struct node{
int s, e, id;
bool operator < (const node nt) const{
if(s != nt.s)
return s < nt.s;
else return e < nt.e;
}
}q[maxn];
int n, m;
int a[maxn];
struct BIT{
int C[maxn];
void init(){
memset(C, 0, sizeof(C));
}
int lowbit(int x){
return -x&x;
}
int sum(int x){
int ret = 0;
while(x > 0){
ret += C[x];
x -= lowbit(x);
}
return ret;
}
void add(int x,int v){
while(x <= n){///这个地方的n是要根据C[]数组需要保存的范围来确定的,不一定就是n
C[x] += v;
x += lowbit(x);
}
}
}bit;
int vis[maxn], prime[maxn], pcnt = 0;
void getprime(){
memset(vis, 0, sizeof(vis));
for(long long i = 2; i < maxn; i++){
if(!vis[i]){
prime[pcnt++] = i;
for(long long j = i*i; j < maxn; j+=i){
vis[j] = 1;
}
}
}
}
vector<int> g[maxn];
void getfac(int id){
g[id].clear();
int tmp;
scanf("%d",&tmp);
for(int i = 0; i < pcnt && prime[i] * prime[i] <= tmp; i++){
if(tmp % prime[i] == 0){
g[id].push_back(prime[i]);
while(tmp % prime[i] == 0)
tmp /= prime[i];
}
}
if(tmp != 1) g[id].push_back(tmp);
}
int l[maxn], r[maxn], pos[maxn];//pos中存的是每个素因子出现的最靠右(左)的位置
vector<int> vec[maxn];
void deal(){
memset(pos, 0, sizeof(pos));
for(int i = 0; i < maxn; i++) vec[i].clear();
for(int i = 1; i <= n; i++){
getfac(i);
l[i] = 1;
for(int j = 0; j < g[i].size(); j++){
int tmp = g[i][j];
l[i] = max(l[i], pos[tmp]+1);//这个地方求出的其实是最左端的互质的位置
pos[tmp] = i;
}
l[i]--;//所以这里位置往左移一个
vec[l[i]].push_back(i);
}
memset(pos, INF, sizeof(pos));
for(int i = n; i >= 1; i--){
r[i] = n;
for(int j = 0; j < g[i].size(); j++){
int tmp = g[i][j];
r[i] = min(r[i], pos[tmp]-1);
pos[tmp] = i;
}
r[i]++;
}
}
void init(){
deal();
int s, e;
for(int i = 0; i < m; i++){
scanf("%d%d",&s,&e);
q[i].id = i;
q[i].s = s;
q[i].e = e;
}
}
int ans[maxn];
void solve(){
sort(q, q+m);
int left = 1;
// for(int i = 1; i <= n; i++){
// printf("left = %d right = %d\n",l[i],r[i]);
// }
// for(int i = 1; i <= n; i ++){
// printf("=== %d : \n",i);
// for(int j = 0; j < vec[i].size(); j++){
// printf("%d ",vec[i][j]);
// }
// if(vec[i].size() != 0)
// printf("\n");
// }
bit.init();
for(int i = 1; i <= n; i++){
if(l[i] < 1){
bit.add(i,1);
if (r[i] <= n)
bit.add(r[i], -1);
}
}
for(int i = 0; i < m; i++){
while(left < q[i].s){
// bit.add(left, -1);//这个地方加不加无所谓,因为以后再也用不到left位置的值了
if (r[left] <= n) bit.add(r[left], 1);
for(int j = 0; j < vec[left].size(); j++){
int k = vec[left][j];
bit.add(k, 1);
if (r[k] <= n) bit.add(r[k], -1);
}
left++;
}
ans[q[i].id] = bit.sum(q[i].e) - bit.sum(q[i].s-1);
}
for(int i = 0; i < m; i++){
printf("%d\n",ans[i]);
}
}
int main(){
getprime();
while(scanf("%d%d",&n,&m) != EOF){
init();
solve();
}
return 0;
}
/*
10 2
2 3 4 5 6 7 8 9 10 11
*/
这个样例完全没有用..我使用它调代码了