[bzoj] 4373算术天才⑨与等差数列

对于一段l至r的等差序列,一定会满足

①任意两数间的差定为k的倍数,即是相邻两数差的绝对值的最小公因数=k

②Max-min=(r-l)*k

③无相同元素 

那么可以直接用线段树进行维护,并注意l==r的情况


#include <cstdio>
#include <algorithm> 
#define lson (num<<1)
#define rson (lson+1)
using namespace std;
int n,m;
int a[300002];
struct WXY{
    int mi,ma,s;
    int ls,rs;
    int l,r;
    void clear()
    {
        mi=ma=s=ls=rs=l=r=0;
    }
}tree[2500002];
inline int gcd(int x,int y)  
{  
    if(x==0)  
        return y;  
    else if(y==0)  
        return x;  
    int m=x%y;  
    while(m!=0)  
    {  
        x=y;  
        y=m;  
        m=x%y;  
    }  
    return y;  
}  
inline int absx(int x)  
{  
    if(x<0)  
        x=-x;  
    return x;  
}  
void updata(int num)
{
    tree[num].ls=tree[lson].ls;
    tree[num].rs=tree[rson].rs;
    int ab=absx(tree[lson].rs-tree[rson].ls);
    tree[num].s=gcd(gcd(tree[lson].s,tree[rson].s),ab);
    tree[num].ma=max(tree[lson].ma,tree[rson].ma);
    tree[num].mi=min(tree[lson].mi,tree[rson].mi);
}
void build_tree(int l,int r,int num)
{
    tree[num].l=l;
    tree[num].r=r;
    if (l==r)
    {
        tree[num].ls=a[l];
        tree[num].rs=a[l];
        tree[num].ma=a[l];
        tree[num].mi=a[l];
        return;
    }
        int mid=(l+r)/2;
        build_tree(l,mid,lson);
        build_tree(mid+1,r,rson);
        updata(num);
}
void change(int num,int l,int r,int x)
{
    if (l<=tree[num].l&&tree[num].r<=r)
    {
        tree[num].ls=x;
        tree[num].rs=x;
        tree[num].ma=x;
        tree[num].mi=x;
        return;
    }
    else
    {
        int mid=(tree[num].l+tree[num].r)/2;
        if (l<=mid)
        change(lson,l,r,x);
        if (r>mid)
        change(rson,l,r,x);
        updata(num);
    }
}
WXY ask(int num,int l,int r)
{
    if (l<=tree[num].l&&tree[num].r<=r) return tree[num];
    else
    {
        int mid=(tree[num].l+tree[num].r)/2;
        WXY ans;
        ans.clear();    
        WXY ans1,ans2;
        bool f1=false;bool f2=false;
        if (l<=mid)
        {
            f1=true;
            ans1=ask(lson,l,r);
        }
        if (r>mid)
        {
            f2=true;
            ans2=ask(rson,l,r);
        }
        if (f1)
        {
            if (f2)
            {
                int xx=absx(ans1.rs-ans2.ls);
                ans.s=gcd(gcd(ans1.s,ans2.s),xx);
                ans.ma=max(ans1.ma,ans2.ma);
                ans.mi=min(ans1.mi,ans2.mi);
                ans.ls=ans1.ls;
                ans.rs=ans2.rs;
            }
            else ans=ans1;
        }
        else ans=ans2;
        return ans;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build_tree(1,n,1);
    int ye=0;
    for (int i=1;i<=m;i++)
    {
        int op=0;int x,y;
        scanf("%d",&op);
        if (op==1)
        {
            scanf("%d%d",&x,&y);
             x=x^ye;
             y=y^ye;
            change(1,x,x,y);
        }
        else
        {
            int l,r,k; 
            scanf("%d%d%d",&l,&r,&k);
            l=l^ye;
            r=r^ye;
            k=k^ye;
            WXY xt=ask(1,l,r);
            if (xt.s==k&&(xt.ma-xt.mi)==k*(r-l)||l==r)
            {
                printf("Yes\n");
                ye++;
            }
            else printf("No\n");
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值