ICPC第二场网络赛补题 L
题目链接link.
线段树调一年
题意:n个100以内数,m次操作,一种操作是给区间 [ l , r ] [l,r] [l,r]的每个数都乘以 w w w,一种操作是询问区间 [ l , r ] [l,r] [l,r]中的数的欧拉函数的区间和。
我对线段树一无所知
具体的做法,魔改线段树,线段树的节点用bitset记录一下100以内的25个质数有没有被用过。区间更新的时候,如果某个区间要修改的质数全都被用过了,就乘以w,否则做dfs,更新到叶子节点的时候乘以w-1.需要注意的是,dfs的时候也要把懒标记下放,不然就会像我一样wa成傻逼。这里特别感谢一下辛格帮我看代码,毕竟我的码风hhh
AC代码:
#include<iostream>
#include<cstdio>
#include<bitset>
#define int long long
using namespace std;
const long long mod=998244353;
int mp[105];
void init()
{
int sum=0;
for(int i=2;i<=100;i++)
{
int ok=0;
for(int j=2;j*j<=i;j++)
{
if(i%j==0) {ok++;break;}
}
if(ok==0)
mp[i]=++sum;
}
return ;
}
struct qaq
{
int l,r;
int value;
int lazy_tag=1;
bitset<30>ok;
}tree[400010];
qaq a[100010];
void oula(int pos,int x)
{
a[pos].lazy_tag=1;
a[pos].l=pos;a[pos].r=pos;
if(x==1)
{
a[pos].value=1;
return ;
}
int ans=x;
for(int i=2;i*i<=x;i++)
{
if(x%i==0)
{
a[pos].ok[ mp[i] ]=1;
ans=ans*(i-1)/i;
while(x%i==0)
{
x/=i;
}
}
}
if(x>=2)
{
a[pos].ok[ mp[x] ]=1;
ans=ans*(x-1)/x;
}
a[pos].value=ans;
return ;
}
void build(int x,int l,int r)
{
tree[x].l=l;
tree[x].r=r;
if(l==r)
{
tree[x]=a[l];
return ;
}
int mid=(l+r)/2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
tree[x].value=tree[x*2].value+tree[x*2+1].value;
tree[x].ok= (tree[x*2].ok&tree[x*2+1].ok);
return ;
}
void push_down(int x)
{
tree[x*2].lazy_tag*=tree[x].lazy_tag;
tree[x*2].value *= tree[x].lazy_tag;
tree[x*2].ok |= tree[x].ok;
tree[x*2].lazy_tag %= mod;
tree[x*2].value %= mod;
tree[x*2+1].lazy_tag *= tree[x].lazy_tag;
tree[x*2+1].value *= tree[x].lazy_tag;
tree[x*2+1].ok |= tree[x].ok;
tree[x*2+1].lazy_tag %= mod;
tree[x*2+1].value %= mod;
tree[x].lazy_tag=1;
return ;
}
void update(int x,int w)
{
if(tree[x].ok[mp[w]]==1)
{
tree[x].lazy_tag *= w;
tree[x].value *= w;
tree[x].lazy_tag %= mod;
tree[x].value %= mod;
return ;
}
if(tree[x].l==tree[x].r)
{
tree[x].value *= (w-1);
tree[x].ok[mp[w]]=1;
tree[x].value %= mod;
return ;
}
push_down(x);
update(x*2,w);
update(x*2+1,w);
tree[x].value=tree[2*x].value+tree[2*x+1].value;
tree[x].value %= mod;
tree[x].ok[mp[w]]=1;
return ;
}
void push_up(int x)
{
tree[x].value=tree[x*2].value+tree[x*2+1].value;
tree[x].value %= mod;
tree[x].ok=tree[2*x].ok & tree[2*x+1].ok;
return ;
}
void change(int x,int l,int r,int w)
{
if(tree[x].l==l&&tree[x].r==r)
{
update(x,w);
return ;
}
if(tree[x].lazy_tag!=1) push_down(x);
int mid=(tree[x].l+tree[x].r)/2;
if(r<=mid) change(x*2,l,r,w);
else if(l>=mid+1) change(x*2+1,l,r,w);
else
{
change(x*2,l,mid,w);
change(x*2+1,mid+1,r,w);
}
push_up(x);
return ;
}
int query(int x,int l,int r)
{
if(tree[x].l==l&&tree[x].r==r)
{
return tree[x].value%mod;
}
if(tree[x].lazy_tag!=1) push_down(x);
int mid=(tree[x].l+tree[x].r)/2;
if(r<=mid)
{
return query(x*2,l,r)%mod;
}
else if(l>=mid+1)
{
return query(x*2+1,l,r)%mod;
}
else
{
return (query(x*2,l,mid)+query(x*2+1,mid+1,r))%mod;
}
}
signed main( )
{
int oxy=0;
init();
int n,m;
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
{
int x;
scanf("%lld",&x);
oula(i,x);
}
build(1,1,n);
while(m--)
{
int op;
scanf("%lld",&op);
if(op==0)
{
int l,r,w;
scanf("%lld%lld%lld",&l,&r,&w);
if(w==1) continue;
else
{
for(int i=2;i*i<=w;i++)
{
if(w%i==0)
{
while(w%i==0)
w/=i,change(1,l,r,i);
}
}
if(w!=1) change(1,l,r,w);
}
}
else if(op==1)
{
int l,r;
scanf("%lld%lld",&l,&r);
int haha=query(1,l,r);
haha %= mod;
if(oxy) printf("\n");
printf("%lld",haha);
oxy++;
}
}
return 0;
}