【题意】有一个序列,有3种操作,一种是把区间里面所有的数变成他的欧拉函数值,第二种是把整个区间的数变成某一个值,第三种是查询区间的和。
【解题方法】
这道题其实用线段树来维护就完全可以了,只有当区间的setv存在时,我们更新下去。具体细节见代码。
【AC 代码】
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=3e5+5;
const int maxm=1e7+5;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
//Euler number
int euler[maxm];
void gao(){
euler[1]=1;
for(int i=2;i<maxm;i++)
euler[i]=i;
for(int i=2;i<maxm;i++)
if(euler[i]==i)
for(int j=i;j<maxm;j+=i)
euler[j]=euler[j]/i*(i-1);//先进行除法是为了防止中间数据的溢出
}
//Segment Tree
struct node{
int l,r;
LL setv;
LL sum;
}Tree[maxn<<2];
void pushup(int rt){
Tree[rt].sum=Tree[rt*2].sum+Tree[rt*2+1].sum;
if(Tree[rt*2].setv==Tree[rt*2+1].setv){
Tree[rt].setv=Tree[rt*2].setv;
}else{
Tree[rt].setv=0;
}
}
void pushdown(int rt){
int m=(Tree[rt].l+Tree[rt].r)/2;
if(Tree[rt].setv){
Tree[rt*2].setv=Tree[rt].setv;
Tree[rt*2+1].setv=Tree[rt].setv;
Tree[rt*2].sum=(m-Tree[rt].l+1)*Tree[rt].setv;
Tree[rt*2+1].sum=(Tree[rt].r-m)*Tree[rt].setv;
Tree[rt].setv=0;
}
}
int A[maxn];
void Build(int l,int r,int rt){
Tree[rt].l=l,Tree[rt].r=r;
Tree[rt].setv=0;
if(l==r){
Tree[rt].sum=Tree[rt].setv=A[l];
return ;
}
int mid=(l+r)/2;
Build(l,mid,rt*2);
Build(mid+1,r,rt*2+1);
pushup(rt);
}
void update1(int L,int R,int v,int rt)
{
if(L==Tree[rt].l&&Tree[rt].r==R){
Tree[rt].setv=v;
Tree[rt].sum=(1LL)*v*(Tree[rt].r-Tree[rt].l+1);
return ;
}
pushdown(rt);
int mid=(Tree[rt].l+Tree[rt].r)/2;
if(R<=mid) update1(L,R,v,rt*2);
else if(L>mid) update1(L,R,v,rt*2+1);
else{
update1(L,mid,v,rt*2);
update1(mid+1,R,v,rt*2+1);
}
pushup(rt);
}
void update2(int L,int R,int rt)
{
if(L==Tree[rt].l&&R==Tree[rt].r&&Tree[rt].setv){
Tree[rt].setv=euler[Tree[rt].setv];
Tree[rt].sum=1LL*Tree[rt].setv*(Tree[rt].r-Tree[rt].l+1);
return ;
}
pushdown(rt);
int mid=(Tree[rt].l+Tree[rt].r)/2;
if(R<=mid) update2(L,R,rt*2);
else if(L>mid) update2(L,R,rt*2+1);
else{
update2(L,mid,rt*2);
update2(mid+1,R,rt*2+1);
}
pushup(rt);
}
LL queryans(int L,int R,int rt){
if(L==Tree[rt].l&&Tree[rt].r==R){
return Tree[rt].sum;
}
pushdown(rt);
int mid=(Tree[rt].l+Tree[rt].r)/2;
if(R<=mid) return queryans(L,R,rt*2);
else if(L>mid) return queryans(L,R,rt*2+1);
else{
return queryans(L,mid,rt*2)+queryans(mid+1,R,rt*2+1);
}
}
int main()
{
int T,n,m;
gao();
T=read();
while(T--){
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++){
A[i]=read();
}
int op,l,r,x;
Build(1,n,1);
for(int i=1; i<=m; i++){
op=read(),l=read(),r=read();
if(op==1){
update2(l,r,1);
}else if(op==2){
x=read();
update1(l,r,x,1);
}else{
LL ans=queryans(l,r,1);
printf("%lld\n",ans);
}
}
}
return 0;
}