题目链接: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排序能保证这样处理的结果是正确的。
恩,不错,是一道好题。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <algorithm> 6 using namespace std; 7 8 #define lz 2*u,l,mid 9 #define rz 2*u+1,mid+1,r 10 const int maxn=50005; 11 int maxx[4*maxn], flag[4*maxn]; 12 int a[maxn]; 13 int pre[maxn]; 14 int n, m, T; 15 vector<int>vt; 16 17 struct node 18 { 19 int l, r, id; 20 int ans; 21 friend bool operator<(const node A, const node B) 22 { 23 return A.r<B.r; 24 } 25 }f[maxn]; 26 27 bool cmp(node A, node B) 28 { 29 return A.id<B.id; 30 } 31 32 void push_down(int u, int l, int r) 33 { 34 if(flag[u]) 35 { 36 flag[2*u]=max(flag[2*u],flag[u]); 37 flag[2*u+1]=max(flag[2*u+1],flag[u]); 38 maxx[2*u]=max(maxx[2*u],flag[u]); 39 maxx[2*u+1]=max(maxx[2*u+1],flag[u]); 40 flag[u]=0; 41 } 42 } 43 44 void Update(int u, int l, int r, int tl, int tr, int val) 45 { 46 maxx[u]=max(maxx[u],val); 47 if(tl<=l&&r<=tr) 48 { 49 flag[u]=max(flag[u],val); 50 maxx[u]=max(maxx[u],val); 51 return ; 52 } 53 push_down(u,l,r); 54 int mid=(l+r)>>1; 55 if(tr<=mid) Update(lz,tl,tr,val); 56 else if(tl>mid) Update(rz,tl,tr,val); 57 else 58 { 59 Update(lz,tl,mid,val); 60 Update(rz,mid+1,tr,val); 61 } 62 } 63 64 int Query(int u, int l, int r, int tl, int tr) 65 { 66 if(tl<=l&&r<=tr) return maxx[u]; 67 push_down(u,l,r); 68 int mid=(l+r)>>1; 69 if(tr<=mid) return Query(lz,tl,tr); 70 else if(tl>mid) return Query(rz,tl,tr); 71 else 72 { 73 int t1=Query(lz,tl,mid); 74 int t2=Query(rz,mid+1,tr); 75 return max(t1,t2); 76 } 77 } 78 79 void Solve(int x, int r) 80 { 81 vt.clear(); 82 vt.push_back(x); 83 for(int i=2; i*i<=x; i++) 84 if(x%i==0) 85 { 86 vt.push_back(i); 87 vt.push_back(x/i); 88 } 89 for(int i=0; i<vt.size(); i++) 90 { 91 int l=pre[ vt[i] ]; 92 pre[ vt[i] ]=r; 93 if(l==-1||l==r) continue; 94 Update(1,1,n,l,l,vt[i]); 95 } 96 } 97 98 int main() 99 { 100 cin >> T; 101 while(T--) 102 { 103 cin >> n; 104 for(int i=1; i<=n; i++) scanf("%d", a+i), pre[i]=-1; 105 cin >> m; 106 for(int i=1; i<=m; i++) f[i].id=i, scanf("%d%d",&f[i].l,&f[i].r); 107 sort(f+1,f+m+1); 108 for(int i=1; i<=4*n; i++) maxx[i]=1, flag[i]=0; 109 int i=1, j=1; 110 while(j<=m) 111 { 112 if(i<=f[j].r&&i<=n) 113 { 114 Solve(a[i],i); 115 i++; 116 } 117 else 118 { 119 if(f[j].l!=f[j].r)f[j].ans=Query(1,1,n,f[j].l,f[j].r); 120 else f[j].ans=0; 121 j++; 122 } 123 } 124 sort(f+1,f+m+1,cmp); 125 for(int i=1; i<=m; i++) 126 printf("%d\n",f[i].ans); 127 } 128 return 0; 129 }