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\n",Q[i].ans); 124 }init(); 125 } 126 return 0; 127 }
转载于:https://www.cnblogs.com/guapisolo/p/9768605.html
HDU 4630 No Pain No Game (线段树+离线)相关推荐
- HDU - 4417 Super Mario(主席树/线段树+离线)
题目链接:点击查看 题目大意:给出由 n 个数的数列,再给出 m 次查询,每次查询需要输出 [ l , r ] 内小于等于 h 的数有多少个 题目分析:大晚上睡不着觉随便做做题,发现这个题目原来可以用 ...
- Super Mario HDU - 4417(主席树解决区间数字小于k的个数||线段树+离线)
Mario is world-famous plumber. His "burly" figure and amazing jumping ability reminded in ...
- HDU 4417 Super Mario(线段树离线处理/主席树)
Mario is world-famous plumber. His "burly" figure and amazing jumping ability reminded in ...
- SPOJ - DQUERY D-query(莫队/线段树+离线/主席树)
题目链接:点击查看 题目大意:给出一个由n个数组成的序列,再给出m次查询,每次查询区间[l,r]中有多少个不同的数 题目分析:莫队模板题,直接套板子就好了 有点意思的是函数返回值为布尔类型,然后没有r ...
- No Pain No Game HDU - 4630(gcd+线段树+离线处理)
Life is a game,and you lose it,so you suicide. But you can not kill yourself before you solve this p ...
- HDU 4630 No Pain No Game 树状数组+离线操作
题意:给一串数字,每次查询[L,R]中两个数的gcd的最大值. 解法:容易知道,要使取两个数让gcd最大,这两个数最好是倍数关系,所以处理出每个数的所有倍数,两两间根据倍数关系形成一条线段,值为该数. ...
- HDU - 1255 覆盖的面积(线段树求矩形面积交 扫描线+离散化)
链接:线段树求矩形面积并 扫描线+离散化 1.给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 2.看完线段树求矩形面积并 的方法后,再看这题,求的是矩形面积交,类同. 求面积时,用被覆 ...
- HDU 1394 Minimum Inversion Number(线段树的单点更新)
点我看题目 题意 :给你一个数列,a1,a2,a3,a4.......an,然后可以求出逆序数,再把a1放到an后,可以得到一个新的逆序数,再把a2放到a1后边,,,,,,,依次下去,输出最小的那个逆 ...
- hdu 5493 Queue(逆序对,线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5493 解题思路: 一道线段树的题目,因为是前面或者后面有k个比自己高的人,所以我们应该按照由身高从小到 ...
- 【HDU - 4217 】Data Structure? (线段树求第k小数)
题干: Data structure is one of the basic skills for Computer Science students, which is a particular w ...
最新文章
- mysql 什么不能用别名_[转]为何group by后面不能使用别名(除MySQL)
- MySQL数据库的高可用方案总结
- 对比tensorflow查看打印输出张量Tensor的两种方法(急切执行tf.enable_eager_execution()和tf.Session.run())
- [转]白话阿里巴巴Java开发手册高级篇
- 使用macOS自带convert,sips命令快速处理图片及转换图片格式
- 怎样追求一个你喜欢的人?
- java 直播_一对一直播源码开发过程中区分Java和PHP的重要性
- 在组件中获取Application
- TableCache设置过小造成MyISAM频繁损坏
- TCP/IP——链路层简记
- CFS之vruntime记录
- 【心电信号】基于matlab自适应滤波算法胎儿心电信号提取【含Matlab源码 953期】
- HP服务器远程管理工具iLO详细介绍
- 照片损坏怎么办,怎么恢复受损照片
- ZOJ Problem 1005 jugs
- 计算机内存条如何区分频率,怎么看内存条频率,详细教您怎么看内存条频率
- 4.5 GPO的编辑
- c语言wb是标识符,C语言文件 "w+"与"wb+"区别
- 关于github双因素验证问题解决方案
- 光脚的快感!仅仅耐克1/8重,一个夏天不会臭脚!徒步不累脚!