您的位置:首页 > 大数据 > 人工智能

【HDU4630 No Pain No Game】 dp思想+线段树的离线操作

2013-08-04 14:20 211 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4630

题意:给你n个数据范围在[1,n]中的数,m个操作,每个操作一个询问[L,R],让你求区间[L,R]内任意两个数的最大公倍数。

思路:是线段树是必然的 O.O 。顺着来不好解决,只能离线处理试试。按r从小到大排序,数组a[i]从左到右扫一遍,对每个a[i]都要进行处理,先因数分解,pre[X]表示约数X在前面最后出现的位置。开始处理的是pre[X]到当前位置r都对约数X进行比较更新,后面想想这样是有问题,因为这样不能保证约数X出现在pre[X]与r的中间位置,所以这里我们只对位置pre[X]进行最大约数的比较更新,这样就能很好的解决当询问[pre[X],r]时,这个约数恰好就出现在区间段内,pre[X]更新为r,起初的对询问区间段r排序能保证这样处理的结果是正确的。

恩,不错,是一道好题。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

#define lz 2*u,l,mid
#define rz 2*u+1,mid+1,r
const int maxn=50005;
int maxx[4*maxn], flag[4*maxn];
int a[maxn];
int pre[maxn];
int n, m, T;
vector<int>vt;

struct node
{
int l, r, id;
int ans;
friend bool operator<(const node A, const node B)
{
return A.r<B.r;
}
}f[maxn];

bool cmp(node A, node B)
{
return A.id<B.id;
}

void push_down(int u, int l, int r)
{
if(flag[u])
{
flag[2*u]=max(flag[2*u],flag[u]);
flag[2*u+1]=max(flag[2*u+1],flag[u]);
maxx[2*u]=max(maxx[2*u],flag[u]);
maxx[2*u+1]=max(maxx[2*u+1],flag[u]);
flag[u]=0;
}
}

void Update(int u, int l, int r, int tl, int tr, int val)
{
maxx[u]=max(maxx[u],val);
if(tl<=l&&r<=tr)
{
flag[u]=max(flag[u],val);
maxx[u]=max(maxx[u],val);
return ;
}
push_down(u,l,r);
int mid=(l+r)>>1;
if(tr<=mid) Update(lz,tl,tr,val);
else if(tl>mid) Update(rz,tl,tr,val);
else
{
Update(lz,tl,mid,val);
Update(rz,mid+1,tr,val);
}
}

int Query(int u, int l, int r, int tl, int tr)
{
if(tl<=l&&r<=tr) return maxx[u];
push_down(u,l,r);
int mid=(l+r)>>1;
if(tr<=mid) return Query(lz,tl,tr);
else if(tl>mid) return Query(rz,tl,tr);
else
{
int t1=Query(lz,tl,mid);
int t2=Query(rz,mid+1,tr);
return max(t1,t2);
}
}

void Solve(int x, int r)
{
vt.clear();
vt.push_back(x);
for(int i=2; i*i<=x; i++)
if(x%i==0)
{
vt.push_back(i);
vt.push_back(x/i);
}
for(int i=0; i<vt.size(); i++)
{
int l=pre[ vt[i] ];
pre[ vt[i] ]=r;
if(l==-1||l==r) continue;
Update(1,1,n,l,l,vt[i]);
}
}

int main()
{
cin >> T;
while(T--)
{
cin >> n;
for(int i=1; i<=n; i++) scanf("%d", a+i), pre[i]=-1;
cin >> m;
for(int i=1; i<=m; i++) f[i].id=i, scanf("%d%d",&f[i].l,&f[i].r);
sort(f+1,f+m+1);
for(int i=1; i<=4*n; i++) maxx[i]=1, flag[i]=0;
int i=1, j=1;
while(j<=m)
{
if(i<=f[j].r&&i<=n)
{
Solve(a[i],i);
i++;
}
else
{
if(f[j].l!=f[j].r)f[j].ans=Query(1,1,n,f[j].l,f[j].r);
else f[j].ans=0;
j++;
}
}
sort(f+1,f+m+1,cmp);
for(int i=1; i<=m; i++)
printf("%d\n",f[i].ans);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: