题意:给定一个序列,动态的询问你这个序列的某个区间两两最大的最大公约数:
解题思路:一个区间的最大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 }
ps。这题卡qsort 好恶心。。。(离线的时候不要对操作进行排序输出了,重开一个数组记录);