hdu 4630 No Pain No Game (线段树+离线)
Posted guapisolo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 4630 No Pain No Game (线段树+离线)相关的知识,希望对你有一定的参考价值。
题目大意:给你一个无序的1~n的排列a,每次询问[l,r]之间任取两个数得到的最大gcd是多少
先对所有询问离线,然后把问题挂在区间的左端点上(右端点也行)
在预处理完质数,再处理一个next数组,表示 i 的任意一个质因子,这样我们分解质因数的时间降低到而不是
因为能对答案产生贡献的都是成对出现的两个数
所以每次记录一个last[i],表示数 i 上一次出现的位置
当遍历到第 i 个数时,分解出它的所有质因数,然后搜出它所有的因子,因子个数大约不会超过,均摊下来就更少了
那么,a[i] 的某个因数 x 就能和 last[x]成为一对,在线段树里的last[x]位置更新答案,即gcd(a[i],a[last[x]]),但不一定是last[x]的最优解,要在last[x]的位置取一个max
询问就是线段树里查询[l,r]的最大值
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #define N 50010 5 #define M 50 6 #define ll long long 7 using namespace std; 8 9 int n,q,cte,num,nson,T; 10 int a[N],pr[N],nxt[N],use[N],head[N]; 11 int son[N],d[N],app[N],pw[N],la[N]; 12 struct node{int l,r,id,ans;}Q[N]; 13 struct Edge{int to,nxt;}edge[N]; 14 void ae(int u,int v){ 15 cte++;edge[cte].to=v;edge[cte].nxt=head[u];head[u]=cte;} 16 int gcd(int x,int y){if(y==0)return x;return gcd(y,x%y);} 17 struct Seg{ 18 #define il inline 19 int ma[N<<2]; 20 il void pushup(int rt){ma[rt]=max(ma[rt<<1],ma[rt<<1|1]);} 21 void build(int l,int r,int rt) 22 { 23 if(l==r) {ma[rt]=1;return;} 24 int mid=(l+r)>>1; 25 build(l,mid,rt<<1),build(mid+1,r,rt<<1|1); 26 pushup(rt); 27 } 28 void update(int x,int l,int r,int rt,int w) 29 { 30 if(l==r){ma[rt]=max(ma[rt],gcd(w,a[l]));return;} 31 int mid=(l+r)>>1; 32 if(x<=mid) update(x,l,mid,rt<<1,w); 33 else update(x,mid+1,r,rt<<1|1,w); 34 pushup(rt); 35 } 36 int query(int L,int R,int l,int r,int rt) 37 { 38 if(L<=l&&r<=R){return ma[rt];} 39 int mid=(l+r)>>1,ans=0; 40 if(L<=mid) ans=max(query(L,R,l,mid,rt<<1),ans); 41 if(R>mid) ans=max(query(L,R,mid+1,r,rt<<1|1),ans); 42 return ans; 43 } 44 #undef il 45 }seg; 46 int gint() 47 { 48 int ret=0,fh=1;char c=getchar(); 49 while(c<‘0‘||c>‘9‘){if(c==‘-‘)fh=-1;c=getchar();} 50 while(c>=‘0‘&&c<=‘9‘){ret=(ret<<3)+(ret<<1)+c-‘0‘;c=getchar();} 51 return ret*fh; 52 } 53 void get_pr() 54 { 55 int cnt=0; 56 for(int i=2;i<N;i++){ 57 if(!use[i]) pr[++cnt]=i,nxt[i]=i; 58 for(int j=1;j<=cnt&&i*pr[j]<N;j++){ 59 use[i*pr[j]]=1,nxt[i*pr[j]]=pr[j]; 60 if(i%pr[j]==0) break; 61 } 62 } 63 } 64 void Div(int x){ 65 num=0;int p; 66 while(x!=1){ 67 num++;p=son[num]=nxt[x];d[num]=0; 68 while(x%p==0) x/=p,d[num]++; 69 } 70 } 71 void dfs_ap(int k){ 72 if(k==num+1){ 73 app[++nson]=1; 74 for(int i=1;i<=num;i++) 75 app[nson]*=pw[i]; 76 return;} 77 pw[k]=1; 78 for(int j=0;j<=d[k];j++) 79 dfs_ap(k+1),pw[k]*=son[k]; 80 } 81 void solve(int k) 82 { 83 Div(a[k]);nson=0;dfs_ap(1); 84 for(int i=1;i<=nson;i++) 85 { 86 if(!la[app[i]]) la[app[i]]=k; 87 else{ 88 seg.update(la[app[i]],1,n,1,app[i]); 89 la[app[i]]=k; 90 } 91 } 92 for(int j=head[k];j;j=edge[j].nxt){ 93 int v=edge[j].to; 94 Q[v].ans=seg.query(Q[v].l,Q[v].r,1,n,1); 95 } 96 } 97 void init() 98 { 99 for(int i=1;i<=n;i++) 100 a[i]=use[N]=head[i]=la[i]=0; 101 for(int i=1;i<=q;i++) 102 Q[i].l=Q[i].r=Q[i].ans=edge[i].to=edge[i].nxt=0; 103 memset(&seg,0,sizeof(seg)); 104 cte=0; 105 } 106 int main() 107 { 108 scanf("%d",&T); 109 get_pr(); 110 for(int t=1;t<=T;t++) 111 { 112 scanf("%d",&n); 113 for(int i=1;i<=n;i++) 114 a[i]=gint(); 115 scanf("%d",&q); 116 for(int i=1;i<=q;i++) 117 Q[i].l=gint(),Q[i].r=gint(),ae(Q[i].l,i); 118 seg.build(1,n,1); 119 for(int i=n;i>=1;i--) 120 solve(i); 121 for(int i=1;i<=q;i++){ 122 if(Q[i].l==Q[i].r) Q[i].ans=0; 123 printf("%d ",Q[i].ans); 124 }init(); 125 } 126 return 0; 127 }
以上是关于hdu 4630 No Pain No Game (线段树+离线)的主要内容,如果未能解决你的问题,请参考以下文章
hdu 4630 No Pain No Game 线段树离线处理
HDU - 4630 No Pain No Game(离线线段树)
hdu 4630 No Pain No Game (线段树+离线)