首页 > 其他分享 >Interval GCD 题解 || WHK废物快乐题

Interval GCD 题解 || WHK废物快乐题

时间:2023-08-22 09:04:59浏览次数:40  
标签:GCD val int 题解 Interval mid build data gcd

题意

给定一个序列,需要对其进行区间加和和查询 \(\gcd\) 操作。

思路

首先看到了区间加和,自然想到是直接打懒标记,但是呢。。。 \(\gcd\) 具有一些特殊性,我们并不能通过向下传递标记的方式维护 \(\gcd\) 。

于是想到昨天 Tad 讲树状数组区间修改的差分数组方案。

我们创建一个数组 b 来维护这个数列的差分值即 \(b_i=a_i-a_{i-1}\),每一次区间修改就对区间的头尾进行单点增加即可。

那么b有什么用呢?请看:

首先在我们刚学递归的时候,老师们就曾讲过《九章算术》中求 \(\gcd\) 的更相减损术:

\(\gcd(x,y)= \gcd(x,y-x)\)

对于这个whk废物来说,证明它确实有点困难,不过通过BDFS的方式,得到了这样的答案:

设 \(gcd(x,y)=k\) ,显然 \(x=k\cdot p_1,y=k\cdot p_2\);

\(\therefore \gcd(y,x-y)=\gcd(p_2\cdot k,k\cdot (p_1-p_2) )=k\)

很好,我们证出来了这个之后可以容易地归纳出:

\(\gcd(a_1,a_2,...a_{n-1},a_n)=\gcd(a_1,a_2-a_1,a_3-a_2,...a_{n-3}-a_{n-2},a_{n}-a{n-1})=\gcd(a_1,\gcd(a_2-a_1,a_3-a_2,...a_{n-3}-a_{n-2},a_{n}-a_{n-1}))\)

我不告诉你其实这个我没有证明出来是瞎猜的

看到最后一个式子了么?\(a_2-a_1,a_3-a_2,...a_{n-3}-a_{n-2},a_{n}-a_{n-1}\) 不就是我们刚刚维护的 \(b\) 数组吗?那么问题就转化成了维护 \(b\) 的 \(\gcd\) 了。

最后还有一点,求 \(\gcd\) 的时候第一个参数 \(a_1\) 怎么求?非常简单,只需要维护一个树状数组来修改 \(a\) ,传入 \(a_l\) 就行了。

那么树状数组怎么区间增加呢?用树状数组维护一个差分数组,修改时更改左右端点,初始化为0表示原本 a[i] 的变化量,然后加上 a[i] 即可。

其实这也可以再打一个维护前缀和的线段树,但是有点麻烦了。

这时候 Q l r 就等价于:gcd(a[l],ask(1,l+1,r))

对于gcd函数来说,我直接采用了 gcc 内置的 __gcd 函数,反正CCF比赛都是能用的(喜)

代码

无坑。

注释版

#include <bits/stdc++.h>
#define gcd __gcd //节约码长... 
#define int long long //坏习惯,但是我用了 
using namespace std;
struct node{
    int l,r,data; //维护的线段树,我采用结构体维护单个节点 
}t[2000005];
int m,n,arr[500005],l,r,a,b[500005],c[500005];
char ch;
// 线段树板子 
void build(int p,int l,int r){
    t[p].l=l,t[p].r=r;
    if(l==r) t[p].data=b[l];
    else{
        int mid=(l+r)>>1;
        build(p*2,l,mid);
        build(p*2+1,mid+1,r);
        t[p].data=gcd(t[p*2].data,t[p*2+1].data); //这里把板子上面的min改为gcd就行了 
    }
}
void change(int p,int x,int v){
    if(t[p].l==t[p].r) t[p].data+=v;
    else{
        int mid=(t[p].l+t[p].r)>>1;
        if(x<=mid) change(p*2,x,v);
        else change(p*2+1,x,v);
        t[p].data=gcd(t[p*2].data,t[p*2+1].data); //l18,s++
    }
}
int ask(int p,int l,int r){
    if(l<=t[p].l&&r>=t[p].r) return abs(t[p].data);
    int mid=(t[p].l+t[p].r)>>1,val=0; //这里val必须初始化为0不然会爆0 
    if(l<=mid) val=gcd(val,ask(p*2,l,r));
    if(r>mid) val=gcd(val,ask(p*2+1,l,r));
    return val;
}
// 树状数组板子,实际上维护的是差分,前缀和即为a[i]的变化量 
inline int lowbit(int x) {return x&-x;}
inline int gs(int x){
	int ans=0;
	for(;x;x-=lowbit(x)) ans+=c[x];
	return ans;
}
inline void add(int x,int y){
	for(;x<=n;x+=lowbit(x)) c[x]+=y;
}
signed main(){ /*因为用了 #define int long long导致函数返回值变成long long而编译器又不允许,
signed又等价于int,所以只能这样子写(其实在编译器宽松的情况下可以不加返回类型和return 0来压行,但是CCF比赛必爆0)*/
    ios::sync_with_stdio(0); //读入优化 
    cin>>n>>m; 
    for(int i=1;i<=n;i++)
        cin>>arr[i],b[i]=arr[i]-arr[i-1]; //维护差分数组 
    build(1,1,n); // 不build_tree见祖宗 
    while(m--){ //循环m次的简便写法,m减到0变成false即停止 
        cin>>ch;
        switch(ch){ //switch开关,稍微比if简单,注意除最后一部分外每个部分结束要加break不然爆0 
            case 'C':
                cin>>l>>r>>a;
                //维护线段树和树状数组的差分
                add(l,a),change(1,l,a);
                change(1,r+1,-a),add(r+1,-a);
                break;
            case 'Q':
                cin>>l>>r;
                // 见上文 
                cout<<gcd(ask(1,l+1,r),arr[l]+gs(l))<<endl;
                break;
        }
    }
    return 0;
}

极速版

无注释版 可以CTJ的代码

#include <bits/stdc++.h>
#define gcd __gcd
#define int long long
using namespace std;
struct node{
    int l,r,data;
}t[2000005];
int m,n,arr[500005],l,r,a,b[500005],c[500005];
char ch;
void build(int p,int l,int r){
    t[p].l=l,t[p].r=r;
    if(l==r) t[p].data=b[l];
    else{
        int mid=(l+r)>>1;
        build(p*2,l,mid);
        build(p*2+1,mid+1,r);
        t[p].data=gcd(t[p*2].data,t[p*2+1].data);
    }
}
void change(int p,int x,int v){
    if(t[p].l==t[p].r) t[p].data+=v;
    else{
        int mid=(t[p].l+t[p].r)>>1;
        if(x<=mid) change(p*2,x,v);
        else change(p*2+1,x,v);
        t[p].data=gcd(t[p*2].data,t[p*2+1].data);
    }
}
int ask(int p,int l,int r){
    if(l<=t[p].l&&r>=t[p].r) return abs(t[p].data);
    int mid=(t[p].l+t[p].r)>>1,val=0;
    if(l<=mid) val=gcd(val,ask(p*2,l,r));
    if(r>mid) val=gcd(val,ask(p*2+1,l,r));
    return abs(val);
}
inline int lowbit(int x) {return x&-x;}
inline int gs(int x){
	int ans=0;
	for(;x;x-=lowbit(x)) ans+=c[x];
	return ans;
}
inline void add(int x,int y){
	for(;x<=n;x+=lowbit(x)) c[x]+=y;
}
signed main(){
    ios::sync_with_stdio(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>arr[i],b[i]=arr[i]-arr[i-1];
    build(1,1,n);
    while(m--){
        cin>>ch;
        switch(ch){
            case 'C':
                cin>>l>>r>>a;
                add(l,a),change(1,l,a);
                if(r<n) change(1,r+1,-a),add(r+1,-a);
                break;
            case 'Q':
                cin>>l>>r;
                cout<<gcd(ask(1,l+1,r),arr[l]+gs(l))<<endl;
                break;
        }
    }
    return 0;
}

各位大犇,点个赞不过分吧QwQ

标签:GCD,val,int,题解,Interval,mid,build,data,gcd
From: https://www.cnblogs.com/LYXOfficial/p/17647189.html

相关文章

  • 2023 年山东省大学生程序设计竞赛 个人题解
    比赛链接现场赛榜单洛谷重现赛重现赛个人下饭操作太多,后程直接开摆,分数不够理想。这比赛严格来说应该比区域赛简单。不过有几题我挺喜欢的。先发出来,C、D、F、H、J题这几天会填坑。A.Orders点击查看题意简述某工厂收到\(n\)个订单,每个订单形如「在第\(a_i\)天前交......
  • 「NOIP2013」货车运输 题解
    「NOIP2013」货车运输前言这道题算是一个稍有思维难度的MST+LCA题目了。稍微卡了一会(0-88-88-88-100(打表)-100(打表)-100(正解)),开始是打了表过了,后面在DCZ的帮助下正解通过(下面注释提到的一个坑)。题目大意给出一张无向图\(G\),有\(n\)个点和\(m\)个边\((x,y)=z\),找到一......
  • 猴王 题解 || 冷门的 pb_ds 库
    猴王前言虽然很久以前(6月)在我们学并查集的时候QYC就给我们讲了左偏树可以拿来做这道题,但是左偏树作为拓展内容还是稍有难度,最近在gcc中看到pb_ds库,发现非常好用,于是就有了这种偷懒解法。pb_ds库pb_ds库是内置于GCC中的一种拓展标准库,可以在CCF系列比赛中使用。pb......
  • 「NOIP2017 普及组」棋盘 题解
    前言一个绿题,风光啊QwQ题面传送门思路怎么走我们定义一个函数dfs(x,y,coin,can,color)x,y表示坐标,coin表示当前的金币数量,color表示当前坐标的颜色,can表示当前是否能施展魔法。再加一个mp数组记录颜色,-1表示无颜色,0表示红色,1表示黄色为什么不直接使用mp[x][y]获取颜......
  • [CF1790F] Timofey and Black-White Tree 题解
    [CF1790F]TimofeyandBlack-WhiteTree题解题目描述ZYH有一棵\(n\)个节点的树,最初\(c_0\)号节点是黑色,其余均为白色。给定操作序列\(c_1,c_2,\cdots,c_{n-1}\),第\(i\)次操作表示将\(c_i\)号节点染黑。每次操作后,输出距离最近的两个黑点间的距离。两点\(u,v\)间......
  • CF1762E Tree Sum 题解
    题意对于一棵\(n\)个节点的树\(T\),定义\(\operatorname{good}(T)\)为真当且仅当边权\(w\in\left\{-1,1\right\}\)且对于任意节点\(u\),均有\(\displaystylef(u)=\prod\limits_{\left(u,v\right)\inE}w\left(u,v\right)=-1\)。求\[\sum\limits_{\operat......
  • RTSP/Onvif视频服务器EasyNVR安防视频云服务调用接口录像会被自动删除的问题解决方案
    EasyNVR安防视频云服务是基于RTSP/Onvif协议接入的视频平台,可支持将接入的视频流进行全平台、全终端的分发,分发的视频流包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等。平台丰富灵活的视频能力,可应用在智慧校园、智慧工厂、智慧水利等场景中。有用户反馈,在使用EasyNVR接入设备......
  • [ABC315G] Ai + Bj + Ck = X (1 <= i, j, k <= N) 题解
    [ABC315G]Ai+Bj+Ck=X(1<=i,j,k<=N)题解题目描述求题目中式子的数量。思路因为\(N\le10^6\),所以考虑枚举\(k\),那么变为求\(ai+bj=x-ck,i,j\in[1,N]\),这个问题可以通过Exgcd算法求解。首先考虑求出一组\(i,j\)的特解\(x',y'\),根据通解\(x=x'+......
  • Codeforces Round 893 (Div. 2) A-C题解
    CF893(Div.2)A.Buttons签到题。两人会优先选择c中的按钮来,避免自己的按钮消耗同时减少对方可选择的按钮。所以c%2==1等价于a的按钮数+1,c%2==0时相当于c按钮不存在,比较ab按钮的数量来得出答案即可。#include<iostream>usingnamespacestd;typedeflonglong......
  • [AGC005C] Tree Restoring 题解
    比较简单的题。思路我们可以把一棵树抽象成一条极长的链上挂了很多的点。观察这样的树的性质。除去中间的每一个\(dis\)至少有两个点的\(a_i=dis\)。考虑这条链的长度为\(s\)。那么对于中间的点,我们可以分两种情况讨论。\(s\)为偶数那么我们必然要求在中间的权值只......