• AcWing 246 区间最大公约数 (线段树)


    题目链接:https://www.acwing.com/problem/content/description/247/

    更相减损术:(gcd(a,b) = gcd(a,a - b))
    可以扩展到 (n) 个数,(gcd(a,b,c) = gcd(a,b-a,c-b))

    于是可以用线段树维护(a)的差分数组(b),查询时的答案即为(gcd(a[L],query(l+1,r))

    细节:

    1. (gcd(a,b) = gcd(a,-b)), 对结果取负
    2. (gcd)(a,b)(0)没有关系
    3. (long long)
    4. (r+1)可能越界,(n+1) 即可
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<stack>
    #include<queue>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 500010;
    
    int n, m;
    ll a[maxn], b[maxn], c[maxn];
    
    char s[10];
    
    struct SEG{
    	ll gc;
    }t[maxn << 2];
    
    ll gcd(ll x, ll y){ return y? gcd(y, x % y) : x; }
    
    void add(ll x, ll y){
    	for(; x <=n ; x += x & (-x))
    		c[x] += y;
    }
    
    ll ask(ll x){
    	ll sum = 0;
    	for(; x ; x -= x & (-x))
    		sum += c[x];
    	return sum;
    }
    
    void pushup(int i){
    	t[i].gc = gcd(t[i << 1].gc, t[i << 1 | 1].gc); 
    } 
    
    void build(int i, int l, int r){
    	if(l == r){
    		t[i].gc = b[l];
    		return;
    	}
    	
    	int mid = (l + r) >> 1;
    	build(i << 1, l, mid); build(i << 1 | 1, mid + 1, r); 
    	pushup(i);
    }
    
    void modify(int i, int l, int r, int p, ll k){
    	if(l == r){
    		t[i].gc += k;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(p <= mid) modify(i << 1, l, mid , p, k);
    	else modify(i << 1 | 1, mid + 1, r, p ,k);
    	pushup(i);
    }
    
    ll query(int i, int l, int r, int x, int y){
    	if(x > y) return 0;
    	if(x <= l && r <= y){
    		return t[i].gc;
    	}
    	int mid = (l + r) >> 1;
    
    	if(y <= mid) return query(i << 1, l, mid, x, y);
    	else if(x > mid) return query(i << 1 | 1, mid + 1 , r, x, y);
    	else return gcd(query(i << 1, l, mid, x, y), query(i << 1 | 1, mid + 1 , r, x, y));
    }
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
    
    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];
    		add(i, b[i]);
    	}
    	b[++n] = -b[n-1];
    	
    	build(1, 1, n);
     	
     	int x, y; ll d;
     	for(int i = 1; i <= m; ++i){
     		scanf("%s%d%d", s, &x, &y);
     		if(s[0] == 'Q'){
     			ll A = ask(x);
     			ll B = query(1, 1, n, x + 1, y);
     			printf("%lld
    ", abs(gcd(A, B)));
    		} else{
    			scanf("%lld", &d);
    			modify(1, 1, n, x, d);
    			modify(1, 1, n, y + 1, -d);
    			add(x, d); add(y + 1, -d); 
    		}
    	}
     	
    	return 0;
    }
    
  • 相关阅读:
    Ubuntu16.04更新源后apt-get update报错的解决方法
    安装Ubuntu16.04 64bit系统时出错的解决方案
    采用Python-Qt5制作置顶透明桌面提醒词/座右铭/便签
    如何手动解析Keras等框架保存的HDF5格式的权重文件
    读取yml配置文件中的值
    添加20位随机数,不重复,可以用来作为发票申请流水等功能
    java 从json串中取出某个字段的值
    Spring事务的两种方式
    (附表设计)超级全面的权限系统设计方案
    nfs 测试
  • 原文地址:https://www.cnblogs.com/tuchen/p/13958108.html
Copyright © 2020-2023  润新知