zoukankan      html  css  js  c++  java
  • CH 4302 Intervavl(线段树维护区间gcd,区间加)

    传送门

    描述
    给定一个长度为N的数列A,以及M条指令 (N≤510^5, M<=10^5),每条指令可能是以下两种之一:
    “C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。
    “Q l r”,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。
    输入格式
    第一行两个整数N,M,第二行N个整数Ai,接下来M行每条指令的格式如题目描述所示。
    输出格式
    对于每个询问,输出一个整数表示答案。
    样例输入
    5 5
    1 3 5 7 9
    Q 1 5
    C 1 5 1
    Q 1 5
    C 3 3 6
    Q 2 4
    样例输出
    1
    2
    4
    数据范围与约定
    N,M≤2
    10^5, l<=r,数据保证任何时刻序列中的数都是不超过2^62-1的正整数。

    不要在意数据不统一的事

    区间gcdgcd好做

    难点在于如何维护区间加

    考虑辗转相减法:
    gcd(x,y)=gcd(x,xy)gcd(x,y)=gcd(x,x-y)

    我们可以将这个东西拓展到三个数:
    gcd(x,y,z)=gcd(x,yx,zy)gcd(x,y,z)=gcd(x,y-x,z-y)

    证明(摘自gsjgsj神仙的blogblog):

    gcd(x,y,z)=agcd(x,y,z)=a,那么必然存在互质的三个数k1,k2,k3k_1,k_2,k_3使x=k1a,y=k2a,z=k3ax=k_1a,y=k_2a,z=k_3a
    那么gcd(x,yx,zy)=gcd(k1a,(k2k1)a,(k3k2)a)gcd(x,y-x,z-y)=gcd(k_1a,(k_2-k_1)a,(k_3-k_2)a)
    由于k1,k2,k3k_1,k_2,k_3互质,则k1,k2k1,k3k2k_1,k_2-k_1,k_3-k_2都必然互质

    那么我们要求的区间gcdgcd就可以变成差分数组gcd(a[l],del[l+1]gcd(a[l],del[l+1],…,del[r])del[r])
    我们发现这时候区间加其实只对应了l,r+1l,r+1的单点加减

    那我们可以先线段树维护区间差分数组的gcdgcd

    再单独维护一个单点值

    最后合起来计算一下gcdgcd就可以了

    复杂度O(nlog2n)O(nlog^2n)

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    inline int read(){
    	char ch=getchar();
    	int res=0,f=1;
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    	return res*f;
    }
    const int N=5000005;
    int  tr[N<<2],bit[N],a[N],n,m;
    inline int lowbit(int x){
    	return (x&(-x));
    }
    inline void update(int pos,int k){
    	for(;pos<=n;pos+=lowbit(pos))bit[pos]+=k;
    }
    inline int bitsum(int pos,int res=0){
    	for(;pos;pos-=lowbit(pos))res+=bit[pos];return res;
    }
    int gcd(int x,int y){
    	return y==0?x:gcd(y,x%y);
    }
    #define lc (u<<1)
    #define rc ((u<<1)|1)
    #define mid ((l+r)>>1)
    inline void pushup(int u){
    	tr[u]=gcd(tr[lc],tr[rc]);
    }
    void buildtree(int u,int l,int r){
    	if(l==r){
    		tr[u]=a[l]-a[l-1];return;
    	}
    	buildtree(lc,l,mid);
    	buildtree(rc,mid+1,r);
    	pushup(u);
    }
    void add(int u,int l,int r,int pos,int k){
    	if(l==r){
    		tr[u]+=k;return;
    	}
    	if(mid<pos)add(rc,mid+1,r,pos,k);
    	else add(lc,l,mid,pos,k);
    	pushup(u);
    }
    int query(int u,int l,int r,int st,int des){
    	if(st<=l&&r<=des){
    		return tr[u];
    	}
    	if(des<=mid)return query(lc,l,mid,st,des);
    	if(mid<st)return query(rc,mid+1,r,st,des);
    	return gcd(query(lc,l,mid,st,des),query(rc,mid+1,r,st,des));
    }
    signed main(){
    	n=read();m=read();
    	for(int i=1;i<=n;i++){
    		a[i]=read();
    	}
    	buildtree(1,1,n);
    	for(int i=1;i<=m;i++){
    		char op[4];
    		scanf("%s",op);
    		switch(op[0]){
    			case 'Q':{
    				int l=read(),r=read();
    				cout<<abs(gcd(bitsum(l)+a[l],query(1,1,n,l+1,r)))<<'
    ';
    				break;
    			}
    			case 'C':{
    				int l=read(),r=read(),v=read();
    				add(1,1,n,l,v);if(r<n)add(1,1,n,r+1,-v);
    				update(l,v);if(r<n)update(r+1,-v);
    				break;
    			}
    		}
    	}
    }
    
  • 相关阅读:
    遥感图像增强方法应用
    如何从优秀的程序员成为伟大的程序员(2)
    略论提问的智慧
    从我的一篇技术文章说开去
    《虎胆龙威4》观后感
    Microsoft Platform SDK 选择
    ‘OpenThread”: undeclared identifier 问题的解决之道
    Java Web整合开发读书笔记
    Python:监控键盘输入、鼠标操作,并将捕获到的信息记录到文件中
    Getting Started with HTTPClient
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/10366325.html
Copyright © 2011-2022 走看看