【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\n",f[i].ans);

127     }

128     return 0;

129 }
View Code

 

你可能感兴趣的:(game)