HDU 4630 No Pain No Game (线段树 + 离线)

题意:给定一个序列,动态的询问你这个序列的某个区间两两最大的最大公约数:

解题思路:一个区间的最大GCD 就是一个在这个区间出现两次的最大约数。。。。这个题的解题思路是,从后往前扫描,对于A[I]的约数,如果后面出现过,则更新后面那个数的线段树节点。离线的原因主要是因为我们目前的状态,只能解决当前的问题,而且后面的询问,又依赖于现在的状态,所以就要对询问的左区间进行从大到小的排序,然后扫描,如果 i 等于一个询问的左边界,则更新询问。

解题代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <string>
  6 #include <math.h>
  7 
  8 using namespace std;
  9 
 10 #define maxn 50005
 11 struct op
 12 {
 13   int l , r ;
 14   int num ,mx;
 15 
 16 }ops[maxn];
 17 struct node
 18 {
 19   int l , r, m ;
 20   int num;
 21 }tree[maxn*4];
 22 int L(int c)
 23 {
 24  return 2*c;
 25 }
 26 int R(int c){
 27   return 2*c + 1;
 28 }
 29 void build(int c ,int p , int v )
 30 {
 31     tree[c].l = p;
 32     tree[c].r = v ;
 33     tree[c].m = (p+v)/2;
 34     tree[c].num = 1;
 35     if(p == v)
 36       return ;
 37     build(L(c),p,tree[c].m);
 38     build(R(c),tree[c].m +1,v);
 39 }
 40 void Pushup(int c)
 41 {
 42     tree[c].num =  tree[L(c)].num > tree[R(c)].num ? tree[L(c)].num:tree[R(c)].num;
 43 }
 44 int up[maxn];
 45 void update(int c, int p , int v)
 46 {
 47     if(tree[c].l == tree[c].r && tree[c].l == p)
 48     {
 49        if(tree[c].num < v)
 50           tree[c].num = v;
 51       return ;
 52     }
 53     if(p <= tree[c].m ) update(L(c),p,v);
 54     else update(R(c),p,v);
 55     Pushup(c);
 56 }
 57 int tmax = 0 ;
 58 void getmax(int c, int p , int v)
 59 {
 60     if(p <= tree[c].l && v >= tree[c].r)
 61     {
 62        if(tree[c].num > tmax)
 63         tmax = tree[c].num ;
 64        return ;
 65     }
 66     if(v <= tree[c].m) getmax(L(c),p,v);
 67     else if(p > tree[c].m) getmax(R(c),p,v);
 68     else {
 69       getmax(L(c),p,tree[c].m);
 70       getmax(R(c),tree[c].m+1,v);
 71     }
 72 }
 73 
 74 
 75 bool cmp(struct op  a , struct op b)
 76 {
 77    return a.l > b.l;
 78 }
 79 int hs[100000];
 80 int a[maxn];
 81 int ans[maxn];
 82 int main()
 83 {
 84   //freopen("1010.in","r",stdin);
 85   //freopen("output.txt","w",stdout);
 86   int t;
 87   scanf("%d",&t);
 88   while(t--)
 89   {
 90       memset(hs,0,sizeof(hs));
 91       memset(up,0,sizeof(up));
 92        int n ,m;
 93       scanf("%d",&n);
 94 
 95       build(1,1,n);
 96       for(int i = 1;i <= n;i ++)
 97         scanf("%d",&a[i]);
 98       scanf("%d",&m);
 99       for(int i =1 ;i <= m;i ++)
100        {
101          scanf("%d %d",&ops[i].l,&ops[i].r);
102          ops[i].num = i  ;
103        }
104       sort(ops+1,ops+1+m,cmp);
105 
106       int k = 1 ;
107       for(int j = n; j >= 1; j --)
108       {
109           int ta = (int)sqrt(a[j]);
110           for(int i = 1; i<= ta ; i ++ )
111           {
112               if(a[j]%i == 0)
113               {
114                   int t1 = a[j]/i;
115                   if(t1 != i)
116                   {
117                     if(hs[i] != 0 && i > up[hs[i]])
118                     {
119                       update(1,hs[i],i);
120                       up[hs[i]]  = i ;
121                     }
122                     hs[i] = j;
123                     if(hs[t1] != 0 && t1 > up[hs[t1]])
124                     {
125                       update(1,hs[t1],t1);
126                       up[hs[t1]] = t1;
127                     }
128                     hs[t1] = j;
129                   }
130                   else{
131                      if(hs[i] != 0 && i > up[hs[i]])
132                      {
133                       update(1,hs[i],i);
134                       up[hs[i]] = i;
135                      }
136                      hs[i] = j;
137                   }
138               }
139           }
140           while(ops[k].l == j )
141           {
142               
143               tmax = 0 ;
144               getmax(1,ops[k].l,ops[k].r);
145               ans[ops[k].num]= tmax;
146               if(ops[k].l == ops[k].r)
147                 ans[ops[k].num] = 0 ;
148               k++;
149           }
150         //   printf("%d
",tree[1].num);
151       }
152       for(int i = 1;i <= m ;i ++)
153         printf("%d
",ans[i]);
154 
155   }
156 
157   return 0 ;
158 }
View Code

ps。这题卡qsort  好恶心。。。(离线的时候不要对操作进行排序输出了,重开一个数组记录);

没有梦想,何谈远方
原文地址:https://www.cnblogs.com/zyue/p/3245841.html