1. 程式人生 > >hdu 4630 No Pain No Game (線段樹+離線)

hdu 4630 No Pain No Game (線段樹+離線)

uil code pri 我們 i++ style src sqrt cst

題目大意:給你一個無序的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\n",Q[i].ans); 124 }init(); 125 } 126 return 0; 127 }

hdu 4630 No Pain No Game (線段樹+離線)