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

题目链接: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
",f[i].ans);
127     }
128     return 0;
129 }
View Code
原文地址:https://www.cnblogs.com/kane0526/p/3236299.html