维护一个
n
n
个数的序列支持两个操作。
1. Change the value at position in the sequence to
V
V
2. Determine the number of interesting contiguous subarrays contained in the interval
[L,R]
[
L
,
R
]
of the sequence.
操作
1
1
:单点修改元素权值
操作 : 查询区间
[l,r]
[
l
,
r
]
内有趣的子串的个数。(有趣的子串指 串内所有元素的最大公约数大于1)
n,m<=105时限4s n , m <= 10 5 时 限 4 s
emm这题对于我这种菜鸡来说是挺好的。
官方题解的思路顺序有些毒瘤….我就说一下我的理解吧
我们考虑直接线段树维护区间内答案的个数。
l+r
l
+
r
区间内的答案为
l
l
的答案 加上 的答案再加上从左区间出发,到达右区间的串的数量。
我们考虑如何维护跨区间答案的数量。
一个子串对答案有贡献,当且仅当串的
GCD
G
C
D
大于
1
1
。问题转化为维护跨区间的 大于
1
1
的有多少个串.
线段树是无法维护跨区间的数据的,对于这种东西,我们可以拆成前缀+后缀的形式。
记录每个区间的前缀 与 后缀
GCD
G
C
D
,
打表或思考发现 两个数的
GCD
G
C
D
不超过最大数的
1/2
1
/
2
,且前缀
GCD
G
C
D
单调递减。
所以前缀
GCD
G
C
D
的种类不超过
log
l
o
g
个,我们可以开
pair
p
a
i
r
记录前缀
GCD
G
C
D
的值与数量。
整个区间的前缀
GCD
G
C
D
长度不超过
L
L
区间的部分直接继承过来。
超过 的部分 就是
L
L
整段区间的 和
R
R
中前缀的 的
GCD
G
C
D
.
如果前缀
GCD
G
C
D
相同,直接数量加到上一个上。
如果前缀
GCD
G
C
D
不同,新建一个
pair
p
a
i
r
数值为算出来的
GCD
G
C
D
. 数量为
R
R
区间前缀的 的数量。
后缀
GCD
G
C
D
同理。
然后我们得到合并区间计算答案时,枚举
L
L
区间的后缀与 区间的前缀。我们发现右移
L
L
区间指针时,其实是去掉了一个数的,所以
R
R
区间的指针也会右移或不动。所以计算时
R
R
区间的指针都是单调右移的。
所以可以 快速得到答案.
然后注意合并区间时代码的细节。。一定要对拍。。
主要就是
线段树的维护前后缀维护跨区间信息,观察
GCD
G
C
D
性质发现只有
log
l
o
g
种不同
GCD
G
C
D
two−pointer
t
w
o
−
p
o
i
n
t
e
r
快速得到答案
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll>par;
#define mp make_pair
#define lson (o<<1)
#define rson (o<<1|1)
const ll MAXN=2e5+5;
inline ll gcd(ll a,ll b){
return b==0?a:gcd(b,a%b);
}
inline ll read(){
ll x=0;char c=getchar();
while(c<'0'||c>'9'){c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x;
}
ll a[MAXN];
struct xds{
vector<par>pre,sub;
ll iting,lm,rm;
}n[MAXN<<2];
inline xds pushup(xds l,xds r){
xds node;
node.lm=l.lm;node.rm=node.rm;
node.pre.clear();node.sub.clear();
for(ll i=0;i<l.pre.size();i++)node.pre.push_back(l.pre[i]);
for(ll i=l.pre.size();i<l.pre.size()+r.pre.size();i++){
ll tem=gcd(l.pre[l.pre.size()-1].first,r.pre[i-l.pre.size()].first);
if(node.pre[node.pre.size()-1].first==tem)node.pre[node.pre.size()-1].second+=r.pre[i-l.pre.size()].second;
else node.pre.push_back(mp(tem,r.pre[i-l.pre.size()].second));
}
for(ll i=0;i<r.sub.size();i++)node.sub.push_back(r.sub[i]);
for(ll i=r.sub.size();i<l.sub.size()+r.sub.size();i++){
ll tem=gcd(r.sub[r.sub.size()-1].first,l.sub[i-r.sub.size()].first);
if(node.sub[node.sub.size()-1].first==tem)node.sub[node.sub.size()-1].second+=l.sub[i-r.sub.size()].second;
else node.sub.push_back(mp(tem,l.sub[i-r.sub.size()].second));
}
node.iting=l.iting+r.iting;
ll polll=l.sub.size()-1,pollr=0,len=l.sub[0].second,lw=0,flag=0;
while(1){
//int tmp=(pollr==r.pre.size())?pollr-1:pollr;
// cout<<tmp<<"fafafa"<<endl;
int tmp=flag?pollr-1:pollr;
while(polll>=0&&gcd(l.sub[polll].first,r.pre[tmp].first)==1)polll--,flag=0;
if(polll<0)break;if(flag)polll--;
len=l.sub[polll].second;
while(pollr+1<=r.pre.size()&&gcd(r.pre[pollr].first,l.sub[polll].first)!=1)
lw+=r.pre[pollr].second,pollr++;
//cout<<node.iting<<" "<<len<<" qwq "<<lw<<" "<<l.sub[polll].first<<" "<<polll<<endl;
if(gcd(l.sub[polll].first,r.pre[pollr-1].first)!=1)node.iting+=len*lw;
if(polll<=0)break;
flag=1;
}
return node;
}
void build(ll o,ll l,ll r){
if(l==r){
n[o].pre.push_back(mp(a[l],1));
n[o].sub.push_back(mp(a[l],1));
n[o].iting=a[l]==1?0:1;
n[o].lm=n[o].rm=l;
return;
}
ll mid=l+r>>1;
build(lson,l,mid);build(rson,mid+1,r);
n[o]=pushup(n[lson],n[rson]);
}
inline void change(ll o,ll l,ll r,ll pos,ll val){
if(l==r){
n[o].pre.clear();n[o].sub.clear();
n[o].pre.push_back(mp(val,1));
n[o].sub.push_back(mp(val,1));
n[o].iting=val==1?0:1;
return;
}
ll mid=l+r>>1;
if(pos<=mid)change(lson,l,mid,pos,val);
else change(rson,mid+1,r,pos,val);
n[o]=pushup(n[lson],n[rson]);
}
inline xds query(ll o,ll l,ll r,ll ql,ll qr){
if(ql<=l&&qr>=r)return n[o];
ll mid=l+r>>1,ans=0;
xds a,b;bool flagl=0,flagr=0;
if(ql<=mid)a=query(lson,l,mid,ql,qr),flagl=1;
if(qr>mid)b=query(rson,mid+1,r,ql,qr),flagr=1;
if(flagl==1&&flagr==1){
return pushup(a,b);
}
else if(flagl)return a;
return b;
}
ll tot,m;
int main(){
// freopen("garaza.in.1a","r",stdin);
// freopen("garaza.out","w",stdout);
tot=read();m=read();
for(ll i=1;i<=tot;i++){
a[i]=read();
}
build(1,1,tot);
for(ll i=1;i<=m;i++){
ll opt,l,r;
opt=read(),l=read(),r=read();
if(opt==1)change(1,1,tot,l,r);
else cout<<query(1,1,tot,l,r).iting<<endl;
}
/* for(int i=1;i<=3;i++){
cout<<i<<":"<<endl;
for(int j=0;j<n[i].pre.size();j++)cout<<n[i].pre[j].first<<" "<<n[i].pre[j].second<<endl;
cout<<endl;
for(int j=0;j<n[i].sub.size();j++)cout<<n[i].sub[j].first<<" "<<n[i].sub[j].second<<endl;
cout<<endl;
}*/
}
/*
13 3
23729 21451 5233 4434 3109 32116 8606 13454 1636 5660 10169 32582 10081
2 1 13
2 1 7
2 8 13
*/