P4256 题解
最近对线段树有点着迷
题意简述
给出序列
-
查询
的最小公倍数 的值。 -
查询
的最大公约数 的值。 -
查询
的公约数个数 的值。 -
将
更改为 。
注:模数
题目分析
乍一看,维护最小公倍数,模数还在变,什么毒瘤题……
但是!注意到
我们考虑使用线段树的每个结点维护
至于查询,
另外要特判模数为
其他大佬都用的压位,但是好像直接记录次数也不会慢特别多,空间也还行
代码实现
#include<bits/stdc++.h> using namespace std; const int P[25]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97}; int n,q,a[300010],l,r,x,ans; char op[2]; struct sep { int a[25]; void init() { memset(a,0,sizeof a); } }tmp;//一个数质因数分解后,每个质数的次数。为了方便就封装了一个结构体。 struct node { int l,r,tag; sep mn,mx; }tr[1200010];//线段树结点 sep max(sep a,sep b) { for(int i=0;i<25;i++) a.a[i]=max(a.a[i],b.a[i]); return a; } sep min(sep a,sep b) { for(int i=0;i<25;i++) a.a[i]=min(a.a[i],b.a[i]); return a; } void pushup(int p) { tr[p].mx=max(tr[p<<1].mx,tr[p<<1|1].mx); tr[p].mn=min(tr[p<<1].mn,tr[p<<1|1].mn); }//更新结点 void addtag(int p,int val) { tr[p].tag=val; tr[p].mn.init(),tr[p].mx.init(); for(int i=0;i<25&&val>1;i++) while(val%P[i]==0) { tr[p].mn.a[i]++; val/=P[i]; } tr[p].mx=tr[p].mn; }//加标记 void pushdown(int p) { if(tr[p].tag) { addtag(p<<1,tr[p].tag); addtag(p<<1|1,tr[p].tag); tr[p].tag=0; } }//懒标记下传 void build(int p,int l,int r) { tr[p].l=l,tr[p].r=r; tr[p].tag=0; if(l==r) { addtag(p,a[l]); tr[p].tag=0; return; } int mid=l+r>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); pushup(p); }//建树 void change(int p,int l,int r,int val) { if(tr[p].l>=l&&tr[p].r<=r) { addtag(p,val); return; } pushdown(p); int mid=tr[p].l+tr[p].r>>1; if(mid>=l) change(p<<1,l,r,val); if(mid<r) change(p<<1|1,l,r,val); pushup(p); }//修改 sep query1(int p,int l,int r) { if(tr[p].l>=l&&tr[p].r<=r) return tr[p].mx; pushdown(p); int mid=tr[p].l+tr[p].r>>1; if(mid<l) return query1(p<<1|1,l,r); if(mid>=r) return query1(p<<1,l,r); return max(query1(p<<1,l,r),query1(p<<1|1,l,r)); }//查询最小公倍数 sep query2(int p,int l,int r) { if(tr[p].l>=l&&tr[p].r<=r) return tr[p].mn; pushdown(p); int mid=tr[p].l+tr[p].r>>1; if(mid<l) return query2(p<<1|1,l,r); if(mid>=r) return query2(p<<1,l,r); return min(query2(p<<1,l,r),query2(p<<1|1,l,r)); }//查询最大公约数 int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); while(q--) { scanf("%s%d%d%d",op,&l,&r,&x); if(op[0]=='L') { ans=1; tmp=query1(1,l,r); for(int i=0;i<25;i++) for(int j=1;j<=tmp.a[i];j++) ans=1ll*ans*P[i]%x;//根据每个质数的次数乘回去 printf("%d\n",ans%x);//一定要 %x !!否则 x=1 时会寄 }//最小公倍数 else if(op[0]=='G') { ans=1; tmp=query2(1,l,r); for(int i=0;i<25;i++) for(int j=1;j<=tmp.a[i];j++) ans=1ll*ans*P[i]%x; printf("%d\n",ans%x); }//最大公约数 else if(op[0]=='C') change(1,l,r,x);//修改 else { ans=1; tmp=query2(1,l,r); for(int i=0;i<25;i++) ans=1ll*ans*(tmp.a[i]+1)%x; printf("%d\n",ans%x); }//公约数的个数实际上就是最大公约数的约数个数 } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端