hdu 4630
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4630
题目大意:1~n,总共个数,任意顺序排列,然后给你m个询问,每个询问有a、b,问你区间a~b的数里面最大gcd是多少(区间内任意两个数都行)。
思路:由于它问的是gcd,那么我们可以先枚举约数,即1~n,对于每个约数去画区间,我们要求的是对于每个区间长度要尽可能的小,比如约数是1的区间,那就是两两相邻的数下面都要画一条1。这里很巧妙地用了一个pre数组,pre[ i ] 表示数字i在当前位置之前,i的倍数,出现的最靠右的位置,也就是在pre[ i ] 和当前位置之前画一条val值为i的线(当前值为i的倍数)。因为只有当询问覆盖整条线时,这条线的val值才有效,而我们处理的查询右端点是一样的,所以我们把线的值全都放在左端点,把所有的询问按照右端点排序,然后从左往右扫过去。用线段树维护,遇到是右端点,直接查询即可。
这里还有一些细节问题,我们可以先把每个数对应的因数全找出来。然后扫到第i个数字值为x,遍历一遍它的所有因子,看看pre[ t ] 有没有,有的话直接更新线段树,然后再更新pre[ t ] =i 。如果用树状数组的话,由于它不能直接查询指定区间的最大值,我们只要查询的是pre[ t ] 到当前处理到的位置i的最大值,这里有一个技巧,对于每个数,本来更新位置在pre[ t ],把它变成 n-pre[ t ] +1,也就是将本来的区间对称了一下,这样就能按照原本的方式查询了,查询的位置是 n-l+1(l是询问的左端点)。试了一下,发现线段树比树状数组慢了一倍。。 = =
比赛的时候,知道这种题目肯定是线段树,可就是想不出来该怎样构建。。 枚举约数、区间、从左往右扫,左端点、离线,哎,神段树啊,慢慢积累吧。。
先是树状数组的,代码如下:
#include
#include
#include
#include
using namespace std;
const int MAXN = 55555 ;
int num[MAXN];
struct Qu
{
int l,r;
int id;
bool operator < (const Qu &tmp) const
{
return r factor[MAXN];
int n;
void get_factor()
{
for(int i=1;i<=n;i++)
factor[i].clear();
for(int i =1;i0)
{
maxx = max(node[pos],maxx);
pos -= lowbit(pos);
}
return maxx;
}
int ans[MAXN];
int pre[MAXN];
int main()
{
get_factor();
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i = 1;i<=n;i++)
{
scanf("%d",&num[i]);
}
int m;
scanf("%d",&m);
for(int i =1;i<=m;i++)
{
scanf("%d%d",&qu[i].l,&qu[i].r);
qu[i].id = i;
}
sort(qu+1,qu+1+m);
memset(pre,0,sizeof(pre));
int k = 1;
init_tree();
for(int i = 1;i<=n;i++)
{
int cur = num[i];
for(int j = 0;j
然后是线段树的(其实就改了一下下):
#include
#include
#include
#include
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int MAXN = 55555 ;
int num[MAXN];
struct Qu
{
int l,r;
int id;
bool operator < (const Qu &tmp) const
{
return r factor[MAXN];
int n;
void get_factor()
{
for(int i=1;i<=n;i++)
factor[i].clear();
for(int i =1;i>1;
if(pos<=m) update(lson,pos,c);
else update(rson,pos,c);
node[rt] = max(node[rt<<1],node[rt<<1|1]);
}
int query(int l,int r,int rt,int a,int b)
{
if(a<=l&&b>=r)
{
return node[rt];
}
int m = l+r>>1;
int cnt1 = 0,cnt2 = 0;
if(a<=m) cnt1 = query(lson,a,b);
if(b>m) cnt2 = query(rson,a,b);
return max(cnt1,cnt2);
}
int ans[MAXN];
int pre[MAXN];
int main()
{
get_factor();
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i = 1;i<=n;i++)
{
scanf("%d",&num[i]);
}
int m;
scanf("%d",&m);
for(int i =1;i<=m;i++)
{
scanf("%d%d",&qu[i].l,&qu[i].r);
qu[i].id = i;
}
sort(qu+1,qu+1+m);
memset(pre,0,sizeof(pre));
int k = 1;
init_tree();
for(int i = 1;i<=n;i++)
{
int cur = num[i];
for(int j = 0;j