您的位置:首页 > 其它

HDU 4777 Rabbit Kingdom【树状数组】

2016-07-12 12:53 302 查看

题意:

给定序列,若干询问,求给定询问区间中互质的数的个数。

分析:

智商太低理解了好久好久,最后还是看别人讲解和代码明白的。参考

设l[i]为位置为i的元素左边第一个与w[i]不互质的数,r[i]为右边第一个与w[i]不互质的数,那么(l[i],r[i])区间内的所有数均与w[i]互质。

假设我们从头开始扫,为了防止重复计算,我们不管i左边的数,那么每遇到i,就把i的贡献加到后面相应的区间[i,r[i])里,实现起来我们就可以用树状数组(或线段树)维护区间互质数的对数和,每遇到i,就add(i,1),add(r[i],−1)。

下面处理询问,首先对所有询问根据区间左端点进行排序,然后我们从头开始扫,设头指针pp=1,每次遇到l[i]=pp时,说明对于左端点在pp之后的询问他是有贡献的,就把他的贡献加到相应的区间中,即[i,r[i]),指针扫过时再进行还原。我们可以用vector保存每个l[i]=pp的元素位置i,然后每次访问到一个位置直接遍历相应的vector即可。

代码:

#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 200000 + 5, oo = 0x3f3f3f3f;
vector<int>prime[maxn];
vector<int>loc[maxn];
int l[maxn], r[maxn];
int w[maxn];
int pos[maxn];
int bit[maxn];
int ans[maxn];
bool isprime[maxn];
int n, q;
struct Q{
int lq; int rq;int num;
bool operator < (const Q &a) const{
return lq < a.lq;
}
};
Q query[maxn];
int h[maxn];
void initprime()
{
int tot = 0;
memset(isprime, false, sizeof(isprime));
memset(h, 0, sizeof(h));
for(int i = 2; i < maxn; i++){
if(!isprime[i]){
h[tot++] = i;
for(int j = 2 * i; j < maxn; j += i){
isprime[j] = true;
}
}
}
for(int i = 0; i < tot; i++){
for(int j = h[i]; j < maxn; j += h[i]){
prime[j].push_back(h[i]);
}
}
}
void add(int i, int x)
{
while(i <= n){
bit[i] += x;
i += i & (-i);
}
}
int sum(int i)
{
int ans = 0;
while(i){
ans += bit[i];
i -= i & (-i);
}
return ans;
}
int main (void)
{
initprime();
while(scanf("%d%d", &n, &q) && (n + q)){
for(int i = 1; i <= maxn; i++){
loc[i].clear();
}
for(int i = 1; i <= n; i++){
scanf("%d", &w[i]);
}
memset(pos, 0, sizeof(pos));
int a;
for(int i = 1; i <= n; i++){
a = 0;
for(int j = 0; j < prime[w[i]].size(); j++){
a = max(a, pos[prime[w[i]][j]]);
pos[prime[w[i]][j]] = i;
}
l[i] = a;
loc[a].push_back(i);
}
a = oo;
memset(pos, 0x3f, sizeof(pos));
for(int i = n; i >= 1; i--){
a = oo;
for(int j = 0; j <  prime[w[i]].size(); j++){
a = min(a, pos[prime[w[i]][j]]);
pos[prime[w[i]][j]] = i;
}
r[i] = a;
}
//for(int i = 1; i <= n; i++)cout<<i<<' '<<l[i]<<' '<<r[i]<<endl;
int tl, tr;
for(int i = 0; i < q; i++){
scanf("%d%d", &query[i].lq, &query[i].rq);
query[i].num = i;
}
sort(query, query + q);
memset(bit, 0, sizeof(bit));
for(int i = 1; i <= n; i++){
if(!l[i]){
add(i, 1);
if(r[i] <= n) add(r[i], -1);
}
}
int pp = 1;
for(int i = 0; i < q; i++){
while(pp < query[i].lq){
add(pp, -1);
if(r[pp] <= n) add(r[pp], 1);
for(int j = 0; j < loc[pp].size(); j++){
add(loc[pp][j], 1);
if(r[loc[pp][j]] <= n) add(r[loc[pp][j]], -1);
}
pp++;
}
ans[query[i].num] = sum(query[i].rq) - sum(query[i].lq - 1);
}
for(int i = 0; i < q; i++){
printf("%d\n", ans[i]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: