luogu P4435 [COCI2017-2018#2] Garaža
题面传送门
发现要维护的东西很奇怪。
想到gcd有性质:一个长度为\(n\)的区间只有\(\min(n,logW)\)种前缀。
然后我们可以合并两个区间,每个区间维护前缀后缀。
就是暴力枚举左右两边看看是不是gcd不为1然后算入答案。
扔到线段树上这样是\(O(nlognlog^2W)\)实际上跑不满。
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 100000
#define K 35
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-4)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
using namespace std;
int n,m,k,A[N+5],op,x,y;
struct Ques{
int L[K+5],Ls[K+5],Lh,R[K+5],Rs[K+5],Rh;ll Ans;Ques(){Lh=Rh=Ans=0;}
I void Make(int x){L[1]=R[1]=x;Ls[1]=Rs[1]=Lh=Rh=1;Ans=(x!=1);}
Ques operator +(const Ques &B)const{
Ques A;A.Ans=Ans+B.Ans;RI i,j,now;for(i=1;i<=Rh;i++){
for(j=1;j<=B.Lh;j++) __gcd(R[i],B.L[j])^1&&(A.Ans+=1ll*Rs[i]*B.Ls[j]);
}
A.Lh=Lh;for(i=1;i<=Lh;i++) A.L[i]=L[i],A.Ls[i]=Ls[i];for(i=1;i<=B.Lh;i++) now=__gcd(B.L[i],A.L[A.Lh]),now^A.L[A.Lh]?(A.L[++A.Lh]=now,A.Ls[A.Lh]=B.Ls[i]):(A.Ls[A.Lh]+=B.Ls[i]);
A.Rh=B.Rh;for(i=1;i<=B.Rh;i++) A.R[i]=B.R[i],A.Rs[i]=B.Rs[i];for(i=1;i<=Rh;i++) now=__gcd(R[i],A.R[A.Rh]),now^A.R[A.Rh]?(A.R[++A.Rh]=now,A.Rs[A.Rh]=Rs[i]):(A.Rs[A.Rh]+=Rs[i]);return A;
}
}Cl,Ans;
namespace Tree{
#define ls now<<1
#define rs now<<1|1
Ques F[N+5<<2];I void Up(int now){F[now]=F[ls]+F[rs];}I void build(int l=1,int r=n,int now=1){if(l==r)return F[now].Make(A[l]);int m=l+r>>1;build(l,m,ls);build(m+1,r,rs);Up(now);}
I void Ins(int x,int y,int l=1,int r=n,int now=1){if(l==r) return F[now].Make(y);int m=l+r>>1;x<=m?Ins(x,y,l,m,ls):Ins(x,y,m+1,r,rs);Up(now);}
I void Qry(int x,int y,int l=1,int r=n,int now=1){if(x<=l&&r<=y){Ans=Ans+F[now];return;}int m=l+r>>1;x<=m&&(Qry(x,y,l,m,ls),0);y>m&&(Qry(x,y,m+1,r,rs),0);}
}
int main(){
//freopen("1.in","r",stdin);
RI i;scanf("%d%d",&n,&m);for(i=1;i<=n;i++) scanf("%d",&A[i]);Tree::build();
while(m--) scanf("%d%d%d",&op,&x,&y),op^2?(Tree::Ins(x,y),0):(Ans=Cl,Tree::Qry(x,y),printf("%lld\n",Ans.Ans));
}