洛谷 P10463 Interval GCD 做题记录
前置芝士:线段树,辗转相减
思路
首先我们有 \(\gcd(a,b)=\gcd(b,a-b)\)。
题目要求区间 \([l,r]\) 的 \(gcd\),等同于求 \(\gcd_{i=l}^{r} a_i\)。
那么根据辗转相减法,上面这个式子等同于 \(\gcd(a_l,\gcd_{i=l+1}^{r} a_i-a_{i-1})\)。
那么这下就简单了。
我们用线段树维护区间的 \(gcd\) 即可。对 \([l,r]\) 区间加,相当于在差分数组上对 \(l\) 单点加和 \(r+1\) 单点减。
时间复杂度:\(O(n\log n)\)。
难点/坑点:因为会用到 \(r+1\) 可能会大于 \(n\) 所以要记得对 \(n\) 加一。
点击查看代码
#include<bits/stdc++.h>
#define int ll
#define pii pair<int,int>
#define pll pair<long long,long long>
#define ll long long
#define i128 __int128
#define mem(a,b) memset((a),(b),sizeof(a))
#define m0(a) memset((a),0,sizeof(a))
#define m1(a) memset(a,-1,sizeof(a))
#define lb(x) ((x)&-(x))
#define lc(x) ((x)<<1)
#define rc(x) (((x)<<1)|1)
#define pb(G,x) (G).push_back((x))
#define For(a,b,c) for(int a=(b);a<=(c);a++)
#define Rep(a,b,c) for(int a=(b);a>=(c);a--)
#define in1(a) a=read()
#define in2(a,b) a=read(), b=read()
#define in3(a,b,c) a=read(), b=read(), c=read()
#define in4(a,b,c,d) a=read(), b=read(), c=read(), d=read()
#define fst first
#define scd second
#define dbg puts("IAKIOI")
using namespace std;
int read() {
int x=0,f=1; char c=getchar();
for(;c<'0'||c>'9';c=getchar()) f=(c=='-'?-1:1);
for(;c<='9'&&c>='0';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
return x*f;
}
void write(int x) { if(x<0) return write(-x); if(x>=10) write(x/10); putchar('0'+x%10); }
const int mod = 998244353;
int qpo(int a,int b) {int res=1; for(;b;b>>=1,a=(a*a)%mod) if(b&1) res=res*a%mod; return res; }
int inv(int a) {return qpo(a,mod-2); }
#define maxn 500050
int n,m,a[maxn];
struct SegT {
int tr[maxn<<2],sum[maxn<<2];
void psu(int idx) {
tr[idx]=__gcd(tr[lc(idx)],tr[rc(idx)]);
sum[idx]=sum[lc(idx)]+sum[rc(idx)];
}
void build(int idx,int l,int r,int a[]) {
if(l==r) {
tr[idx]=a[l]-a[l-1];
sum[idx]=a[l]-a[l-1];
return ;
}
int mid=l+r>>1;
build(lc(idx),l,mid,a);
build(rc(idx),mid+1,r,a);
psu(idx);
}
void upd(int idx,int l,int r,int k,int val) {
if(l==r) return tr[idx]+=val,sum[idx]+=val,void();
int mid=l+r>>1;
if(k<=mid) upd(lc(idx),l,mid,k,val);
else upd(rc(idx),mid+1,r,k,val);
psu(idx);
}
int qgcd(int idx,int l,int r,int L,int R) {
if(L<=l&&r<=R) return tr[idx];
int res=0,mid=l+r>>1;
if(L<=mid) res=qgcd(lc(idx),l,mid,L,R);
if(R>mid) res=__gcd(res,qgcd(rc(idx),mid+1,r,L,R));
return res;
}
int qsum(int idx,int l,int r,int L,int R) {
if(L<=l&&r<=R) return sum[idx];
int res=0,mid=l+r>>1;
if(L<=mid) res=qsum(lc(idx),l,mid,L,R);
if(R>mid) res+=qsum(rc(idx),mid+1,r,L,R);
return res;
}
}segtr;
void work() {
in2(n,m);
For(i,1,n) in1(a[i]);
segtr.build(1,1,n+1,a);
For(i,1,m) {
char ch=getchar();
while(ch!='C'&&ch!='Q') ch=getchar();
int l,r; in2(l,r);
if(ch=='C') {
int d=read();
segtr.upd(1,1,n+1,l,d);
segtr.upd(1,1,n+1,r+1,-d);
} else {
cout<<abs(__gcd(segtr.qgcd(1,1,n+1,l+1,r),segtr.qsum(1,1,n+1,1,l)))<<'\n';
}
}
}
signed main() {
// freopen("data.in","r",stdin);
// freopen("myans.out","w",stdout);
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
double stt=clock();
int _=1;
// _=read();
// cin>>_;
For(i,1,_) {
work();
}
cerr<<"\nTotal Time is:"<<(clock()-stt)*1.0/1000<<" second(s)."<<'\n';
return 0;
}
本文来自博客园,作者:coding_goat_qwq,转载请注明原文链接:https://www.cnblogs.com/CodingGoat/p/18798205

浙公网安备 33010602011771号