C27 线段树 区间最大公约数

视频链接:214 线段树 区间最大公约数_哔哩哔哩_bilibili

 

 

CH4302 Interval GCD

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define ls u<<1
#define rs u<<1|1
const int N=500010;
typedef long long LL;
int n,m; LL a[N],b[N];
struct Tree{ //线段树
  int l,r;
  LL sum,d; //差分序列的区间和,最大公约数
}tr[N*4];

LL gcd(LL a,LL b){
  return b ? gcd(b,a%b) : a;
}
void pushup(Tree &u,Tree l,Tree r){
  u.sum=l.sum+r.sum;
  u.d=gcd(l.d,r.d);
}
void build(int u,int l,int r){ //建树
  tr[u]={l,r,b[l],b[l]};
  if(l==r) return;
  int mid=l+r>>1;
  build(ls,l,mid);
  build(rs,mid+1,r);
  pushup(tr[u],tr[ls],tr[rs]);
}
void change(int u,int x,LL v){ //点修
  if(tr[u].l==tr[u].r){
    tr[u].sum+=v; tr[u].d+=v;
    return;
  }
  int mid=tr[u].l+tr[u].r>>1;
  if(x<=mid) change(ls,x,v);
  else change(rs,x,v);
  pushup(tr[u],tr[ls],tr[rs]);
}
Tree query(int u,int l,int r){ //区查
  if(l<=tr[u].l && tr[u].r<=r) return tr[u];
  int mid=tr[u].l+tr[u].r>>1;
  if(r<=mid) return query(ls,l,r);
  if(l>mid) return query(rs,l,r);
  Tree T; //开一个临时节点,存储拼凑结果
  pushup(T,query(ls,l,r),query(rs,l,r));
  return T;
}
int main(){
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++) 
    scanf("%lld",&a[i]), b[i]=a[i]-a[i-1];
  build(1,1,n);
  while(m --){
    char c[1]; int l,r; scanf("%s%d%d",c,&l,&r);
    if(*c=='C'){
      LL v; scanf("%lld",&v); 
      change(1,l,v);
      if(r+1<=n) change(1,r+1,-v); //r=n时,越界
    }
    else{
      Tree L, R={0,0,0,0};
      L=query(1,1,l);     //a[l]=sum(b[1~l])
      if(l+1<=r) R=query(1,l+1,r);//b[l+1~r]的gcd
      printf("%lld\n",abs(gcd(L.sum, R.d)));
    }
  }
  return 0;
}

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define ls u<<1
#define rs u<<1|1
const int N=500010;
typedef long long LL;
int n,m; LL a[N],b[N];
struct Tree{ //线段树
  int l,r;
  LL sum,d; //差分序列的区间和,最大公约数
}tr[N*4];

LL gcd(LL a,LL b){
  return b ? gcd(b,a%b) : a;
}
void pushup(Tree &u,Tree l,Tree r){
  u.sum=l.sum+r.sum;
  u.d=gcd(l.d,r.d);
}
void build(int u,int l,int r){ //建树
  tr[u]={l,r,b[l],b[l]};
  if(l==r) return;
  int mid=l+r>>1;
  build(ls,l,mid);
  build(rs,mid+1,r);
  pushup(tr[u],tr[ls],tr[rs]);
}
void change(int u,int x,LL v){ //点修
  if(tr[u].l==tr[u].r){
    tr[u].sum+=v; tr[u].d+=v;
    return;
  }
  int mid=tr[u].l+tr[u].r>>1;
  if(x<=mid) change(ls,x,v);
  else change(rs,x,v);
  pushup(tr[u],tr[ls],tr[rs]);
}
Tree query(int u,int l,int r){ //区查
  if(l<=tr[u].l && tr[u].r<=r) return tr[u];
  int mid=tr[u].l+tr[u].r>>1;
  Tree T,T1={0,0,0,0},T2={0,0,0,0};
  if(l<=mid) T1=query(ls,l,r);
  if(r>mid) T2=query(rs,l,r);
  pushup(T,T1,T2);
  return T;
}
int main(){
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++) 
    scanf("%lld",&a[i]), b[i]=a[i]-a[i-1];
  build(1,1,n+1);
  while(m --){
    char c[1]; int l,r; scanf("%s%d%d",c,&l,&r);
    if(*c=='C'){
      LL v; scanf("%lld",&v); 
      change(1,l,v);
      change(1,r+1,-v);
    }
    else{
      Tree L, R={0,0,0,0};
      L=query(1,1,l);   //a[l]=sum(b[1~l])
      R=query(1,l+1,r); //b[l+1~r]的gcd
      printf("%lld\n",abs(gcd(L.sum, R.d)));
    }
  }
  return 0;
}

 

Luogu P1890 gcd区间

 

posted @ 2023-08-18 15:01  董晓  阅读(459)  评论(0编辑  收藏  举报