Codeforces 1109E. Sasha and a Very Easy Test 线段树
原文链接https://www.cnblogs.com/zhouzhendong/p/CF1109E.html
题意
给定一个长度为 n 的数列 a,以及一个模数 M(不一定是质数)。
要求支持 q 次以下操作:
区间乘
单点除(保证能够整除)
区间求和,最终结果对 M 取模输出。
$$n,q\leq 10^5$$
题解
这里我们设 $f(x)$ 表示 $\frac x {\gcd(x,M)}$ 。
令 $c(x,i)$ 表示 x 最多能够整除 M 的第 $i$ 个质因子的 $c(x,i)$ 次方。
线段树维护一下单点 $f(x)$ 值,以及所有单点 $c(x,i)$;再维护一下所有区间和就好了。
暴写一通,注意取模。这题为什么会放E……
代码
#include <bits/stdc++.h> #define clr(x) memset(x,0,sizeof (x)) using namespace std; typedef long long LL; LL read(){ LL x=0,f=0; char ch=getchar(); while (!isdigit(ch)) f|=ch=='-',ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return f?-x:x; } const int N=100005; int n,mod,phi; int a[N]; vector <int> fenjie(int n){ static vector <int> ans; ans.clear(); for (int i=2;i*i<=n;i++) while (n%i==0) n/=i,ans.push_back(i); if (n>1) ans.push_back(n); return ans; } void Unique(vector <int> &v){ sort(v.begin(),v.end()); int u=unique(v.begin(),v.end())-v.begin(); while (v.size()>u) v.pop_back(); } int Phi(int n){ int ans=n; for (int i=2;i*i<=n;i++) if (n%i==0){ ans=ans/i*(i-1); while (n%i==0) n/=i; } if (n>1) ans=ans/n*(n-1); return ans; } int Pow(int x,int y,int mod=::mod){ int ans=1; for (;y;y>>=1,x=(LL)x*x%mod) if (y&1) ans=(LL)ans*x%mod; return ans; } int Inv(int x){ return Pow(x,phi-1); } vector <int> pm; const int S=40; int pcnt; int ti[N<<2][S],val[N<<2],add[N<<2],nad[N<<2]; void pushdown(int rt){ int ls=rt<<1,rs=ls|1; for (int i=1;i<=pcnt;i++){ ti[ls][i]+=ti[rt][i]; ti[rs][i]+=ti[rt][i]; ti[rt][i]=0; } val[ls]=(LL)val[ls]*add[rt]%mod; val[rs]=(LL)val[rs]*add[rt]%mod; add[ls]=(LL)add[ls]*add[rt]%mod; add[rs]=(LL)add[rs]*add[rt]%mod; add[rt]=1; nad[ls]=(LL)nad[ls]*nad[rt]%mod; nad[rs]=(LL)nad[rs]*nad[rt]%mod; nad[rt]=1; } void pushup(int rt){ val[rt]=(val[rt<<1]+val[rt<<1|1])%mod; } void Get(int v,int &ans,int *c){ for (int i=1;i<=pcnt;i++) while (v%pm[i-1]==0) v/=pm[i-1],c[i]++; ans=v%mod; } void build(int rt,int L,int R){ add[rt]=nad[rt]=1,clr(ti[rt]); if (L==R){ val[rt]=a[L]%mod; Get(a[L],nad[rt],ti[rt]); return; } int mid=(L+R)>>1,ls=rt<<1,rs=ls|1; build(ls,L,mid); build(rs,mid+1,R); pushup(rt); } void update1(int rt,int L,int R,int xL,int xR,int v,int *d,int nv){ if (R<xL||L>xR) return; if (xL<=L&&R<=xR){ for (int i=1;i<=pcnt;i++) ti[rt][i]+=d[i]; val[rt]=(LL)val[rt]*v%mod; add[rt]=(LL)add[rt]*v%mod; nad[rt]=(LL)nad[rt]*nv%mod; return; } pushdown(rt); int mid=(L+R)>>1,ls=rt<<1,rs=ls|1; update1(ls,L,mid,xL,xR,v,d,nv); update1(rs,mid+1,R,xL,xR,v,d,nv); pushup(rt); } int Calc(int v,int *c){ for (int i=1;i<=pcnt;i++) v=(LL)v*Pow(pm[i-1],c[i])%mod; return v; } void update2(int rt,int L,int R,int x,int v,int *d,int nv){ if (L==R){ nad[rt]=(LL)nad[rt]*Inv(nv)%mod; for (int i=1;i<=pcnt;i++) ti[rt][i]-=d[i]; val[rt]=Calc(nad[rt],ti[rt]); return; } pushdown(rt); int mid=(L+R)>>1,ls=rt<<1,rs=ls|1; if (x<=mid) update2(ls,L,mid,x,v,d,nv); else update2(rs,mid+1,R,x,v,d,nv); pushup(rt); } int Query(int rt,int L,int R,int xL,int xR){ if (R<xL||L>xR) return 0; if (xL<=L&&R<=xR) return val[rt]; pushdown(rt); int mid=(L+R)>>1,ls=rt<<1,rs=ls|1; return (Query(ls,L,mid,xL,xR)+Query(rs,mid+1,R,xL,xR))%mod; } int main(){ n=read(),mod=read(),phi=Phi(mod); for (int i=1;i<=n;i++) a[i]=read(); pm=fenjie(mod); Unique(pm); pcnt=pm.size(); build(1,1,n); int q=read(); while (q--){ static int cc[S]; int type=read(),a=read(),b=read(); clr(cc); if (type==1){ int x=read(),v; Get(x,v,cc); update1(1,1,n,a,b,x,cc,v); } else if (type==2){ int v; Get(b,v,cc); update2(1,1,n,a,b,cc,v); } else { printf("%d\n",Query(1,1,n,a,b)); } } return 0; }