您的位置:首页 > 产品设计 > UI/UE

HDU - 5869 Different GCD Subarray Query 树状数组离线处理

2017-09-02 23:45 465 查看
传送门:HDU5869

题意:给出一个长度为n的序列和m次询问,每次询问给出l,r,求[l, r]区间内所有子序列不同gcd的个数。

思路:首先明确对于一个序列a[l...r]的所有以a[l]开头的子序列,所能得到的不同gcd的个数最多有log(a[l])个。那么这个题中我们就可以对于每一个位置,预处理出以该位置为结尾的所有不同gcd的最大左边界(即L至少要到这个位置才能在L~R这个区间中能形成这个gcd),然后将所有询问按右端点排序,每次处理询问的时候将所有小于r的位置预处理出来的值用树状数组维护一下就好了。

代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int> P;
const int MAXN = 1000100;
struct node{
int l, r, id;
bool operator < (node a) const
{
return r < a.r;
}
}Q[MAXN];
int bit[MAXN], a[MAXN];
void add(int i, int x)
{
while(i < MAXN)
{
bit[i] += x;
i += i & -i;
}
}
int sum(int i)
{
int res = 0;
while(i)
{
res += bit[i];
i -= i & -i;
}
return res;
}
vector<P> gcd[MAXN];
int book[MAXN], ans[MAXN];
int main()
{
int n, q, tmp, id;
while(cin >> n >> q)
{
memset(book, 0, sizeof(book));
memset(bit, 0, sizeof(bit));
for(int i = 1; i <= n; i++)
scanf("%d", a + i), gcd[i].clear();
for(int i = 1; i <= n; i++)
{
gcd[i].push_back(P(a[i], i));
for(int j = 0; j < gcd[i - 1].size(); j++)
{
tmp = __gcd(a[i], gcd[i - 1][j].first);
if(tmp != gcd[i][gcd[i].size() - 1].first)
gcd[i].push_back(P(tmp, gcd[i - 1][j].second));
}
}
for(int i = 0; i < q; i++)
scanf("%d %d", &Q[i].l, &Q[i].r), Q[i].id = i;
sort(Q, Q + q);
int last = 1;
for(int i = 0; i < q; i++)
{
while(last <= Q[i].r)
{
for(int j = 0; j < gcd[last].size(); j++)
{
tmp = gcd[last][j].first;
id = gcd[last][j].second;
if(book[tmp])
{
if(book[tmp] < id)
{
add(book[tmp], -1);
add(id, 1);
book[tmp] = id;
}
}
else
{
add(id, 1);
book[tmp] = id;
}
}
last++;
}
ans[Q[i].id] = sum(Q[i].r) - sum(Q[i].l - 1);
}
for(int i = 0; i < q; i++)
printf("%d\n", ans[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: