标签:
对于每个询问,单独一行输出答案。
5
2 3 4 5 6
3
1 1 5
0 2 3 6
1 2 3
32
48
我们先看一下
其中p1, p2……pn为x的所有质因数,x是不为0的整数。
再看一下数据范围,,这也就意味着
因为是区间查询/修改,当然是开线段树了。
600以内的素因子有109个,所以我们就种109棵线段树维护每一段区间的含有该素数的
在维护格式的同时,我们也维护这段区间
我们把通式分成两部分,
我们把修改时的
当我们给某段区间乘上一个质因数
对于那
对于剩下的那
综上所述,该区间乘上了素数
懒惰标记下传,更新方法跟上面的一样,至于查询,答案就是对应的多段区间的欧拉函数积的积。
const
mo=100000007;
var
bz:array[0..600] of boolean;
a,ss,ny:array[0..30000] of int64;
la:array[0..50000,0..109] of longint;
tr:array[0..50000,0..109] of int64;
j,k,l,i,oo,p,n,q,pd,x,y,z:longint;
ans:int64;
function ksm(o,t:int64):int64;
var
cqy:int64;
begin
cqy:=1;
while t>0 do
begin
if t mod 2=1 then cqy:=cqy*o mod mo;
t:=t div 2;
o:=o*o mod mo;
end;
exit(cqy);
end;
procedure jl(o,l,r:longint);
var
i,mid:longint;
begin
if l=r then
begin
tr[o,0]:=a[l];
for i:=1 to oo do
if a[l] mod ss[i]=0 then
begin
inc(tr[o,i]);
tr[o,0]:=tr[o,0]*(ss[i]-1) div ss[i];
end;
exit;
end;
mid:=(l+r) div 2;
jl(o*2,l,mid);
jl(o*2+1,mid+1,r);
tr[o,0]:=tr[o*2,0]*tr[o*2+1,0] mod mo;
for i:=1 to oo do
tr[o,i]:=tr[o*2,i]+tr[o*2+1,i];
end;
procedure gx(o,l,r,ll,rr,k:longint);
var
i,mid,ls,rs:longint;
begin
if (l=ll) and (r=rr) then
begin
la[o,k]:=la[o,k]+1;
tr[o,0]:=(tr[o,0]*ksm(ss[k]-1,r-l+1-tr[o,k]) mod mo)*ksm(ss[k],tr[o,k]) mod mo;
tr[o,k]:=r-l+1;
exit;
end;
mid:=(l+r) div 2;
ls:=o*2;
rs:=ls+1;
for i:=1 to oo do
if la[o,i]>0 then
begin
tr[ls,0]:=(tr[ls,0]*ksm(ss[i]-1,mid-l+1-tr[ls,i]) mod mo)
*ksm(ss[i],tr[ls,i]) mod mo;
tr[rs,0]:=(tr[rs,0]*ksm(ss[i]-1,r-mid-tr[rs,i]) mod mo)
*ksm(ss[i],tr[rs,i]) mod mo;
tr[ls,0]:=tr[ls,0]*ksm(ss[i],(mid-l+1)*(la[o,i]-1)) mod mo;
tr[rs,0]:=tr[rs,0]*ksm(ss[i],(r-mid)*(la[o,i]-1)) mod mo;
tr[ls,i]:=mid-l+1;
tr[rs,i]:=r-mid;
la[ls,i]:=la[ls,i]+la[o,i];
la[rs,i]:=la[rs,i]+la[o,i];
la[o,i]:=0;
end;
if rr<=mid then gx(ls,l,mid,ll,rr,k)
else if ll>mid then gx(rs,mid+1,r,ll,rr,k)
else
begin
gx(ls,l,mid,ll,mid,k);
gx(rs,mid+1,r,mid+1,rr,k);
end;
for i:=1 to oo do
tr[o,i]:=tr[ls,i]+tr[rs,i];
tr[o,0]:=tr[ls,0]*tr[rs,0] mod mo;
end;
procedure cx(o,l,r,ll,rr:longint);
var
i,mid,ls,rs:longint;
begin
if (l=ll) and (r=rr) then
begin
ans:=ans*tr[o,0] mod mo;
exit;
end;
mid:=(l+r) div 2;
ls:=o*2;
rs:=ls+1;
for i:=1 to oo do
if la[o,i]>0 then
begin
tr[ls,0]:=(tr[ls,0]*ksm(ss[i]-1,mid-l+1-tr[ls,i]) mod mo)
*ksm(ss[i],tr[ls,i]) mod mo;
tr[rs,0]:=(tr[rs,0]*ksm(ss[i]-1,r-mid-tr[rs,i]) mod mo)
*ksm(ss[i],tr[rs,i]) mod mo;
tr[ls,0]:=tr[ls,0]*ksm(ss[i],(mid-l+1)*(la[o,i]-1)) mod mo;
tr[rs,0]:=tr[rs,0]*ksm(ss[i],(r-mid)*(la[o,i]-1)) mod mo;
tr[ls,i]:=mid-l+1;
tr[rs,i]:=r-mid;
la[ls,i]:=la[ls,i]+la[o,i];
la[rs,i]:=la[rs,i]+la[o,i];
la[o,i]:=0;
end;
if rr<=mid then cx(ls,l,mid,ll,rr)
else if ll>mid then cx(rs,mid+1,r,ll,rr)
else
begin
cx(ls,l,mid,ll,mid);
cx(rs,mid+1,r,mid+1,rr);
end;
for i:=1 to oo do
tr[o,i]:=tr[ls,i]+tr[rs,i];
tr[o,0]:=tr[ls,0]*tr[rs,0] mod mo;
end;
begin
readln(n);
for i:=1 to n do
read(a[i]);
for i:=2 to 600 do
if bz[i]=false then
begin
inc(oo);
ss[oo]:=i;
for l:=i to 600 div i do
bz[i*l]:=true;
end;
jl(1,1,n);
readln(q);
for l:=1 to q do
begin
read(pd);
if pd=1 then
begin
readln(x,y);
ans:=1;
cx(1,1,n,x,y);
writeln(ans);
end
else
begin
readln(x,y,z);
for i:=1 to oo do
while z mod ss[i]=0 do
begin
gx(1,1,n,x,y,i);
z:=z div ss[i];
end;
end;
end;
end.
JZOJ 4638 第三条跑道 【NOIP2016提高组A组7.16】
标签:
原文地址:http://blog.csdn.net/xianhaoming/article/details/51938814