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

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

BZOJ
标准的做法似乎是线段树维护原数组的最大最小值,差分数组的gcd以及pre数组的最大值
pre表示上一个与该数值相同的下标(然后这个修改我不太会,好像是用个set搞一搞)
那么蒟蒻用一种更快的方法过掉此题
可以线段树维护最小值以及平方和和立方和(对大质数取模)
我只能说这样非常难卡,非常非常难卡,如果有hack数据欢迎下方评论
\[a_1^2+(a_1+d)^2+...+[a_1+(n-1)d]^2=na_1^2+n(n-1)a_1d+\frac{n(n-1)(2n-1)}{6}d^2\]
\[a_1^3+(a_1+d)^3+...+[a_1+(n-1)d]^3=na_1^3+\frac{3n(n-1)a_1^2d}{2}+\frac{n(n-1)(2n-1)a_1d^2}{2}+\frac{n^2(n-1)^2}{4}d^3\]

#define ll long long
#define ls x<<1,l,mid
#define rs x<<1|1,mid+1,r
#include<bits/stdc++.h>
using namespace std;
const int _=3e5+5,p=1e9+7;
int re(){
    int x=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}
int n,m,yes,Mn,S2,S3,inv2=500000004,inv4=250000002,inv6=166666668;
int mn[_<<2],s2[_<<2],s3[_<<2];
inline int js2(ll s,ll x,ll d){
    return ((x*s%p*s%p+x*(x-1)%p*s%p*d%p)%p+
            (x*(x-1)%p*(2*x-1)%p*inv6%p*d%p*d%p)%p)%p;
}
inline int js3(ll s,ll x,ll d){
    return ((x*s%p*s%p*s%p+x*(x-1)*inv2%p*3%p*s%p*s%p*d%p)%p+
            (x*(x-1)%p*inv2%p*(2*x-1)%p*s%p*d%p*d%p+
             x*x%p*(x-1)%p*(x-1)%p*inv4%p*d%p*d%p*d%p)%p)%p;
}
inline void in(int x,int v){
    mn[x]=v;s2[x]=1ll*v*v%p;s3[x]=1ll*v*v%p*v%p;
}
inline void pu(int x){
    int L=x<<1,R=x<<1|1;
    mn[x]=min(mn[L],mn[R]);
    s2[x]=(s2[L]+s2[R])%p;s3[x]=(s3[L]+s3[R])%p;
}
void bu(int x,int l,int r){
    if(l==r){in(x,re());return;}
    int mid=(l+r)>>1;bu(ls);bu(rs);pu(x);
}
void upd(int x,int l,int r,int k,int v){
    if(l==r){in(x,v);return;}
    int mid=(l+r)>>1;if(k<=mid)upd(ls,k,v);
    else upd(rs,k,v);pu(x);
}
void q(int x,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
        Mn=min(Mn,mn[x]);S2=(S2+s2[x])%p;
        S3=(S3+s3[x])%p;return;
    }
    int mid=(l+r)>>1;if(ql<=mid)q(ls,ql,qr);
    if(qr>mid)q(rs,ql,qr);
}
int main(){
    n=re(),m=re();bu(1,1,n);
    int op,x,y,k;
    while(m--){
        op=re(),x=re()^yes,y=re()^yes;
        if(op==1)upd(1,1,n,x,y);
        else{
            Mn=1e9+1;S2=S3=0;
            k=re()^yes;q(1,1,n,x,y);
            ll sum2=js2(Mn,y-x+1,k);
            ll sum3=js3(Mn,y-x+1,k);
            if((sum2==S2&&sum3==S3)||y-x==0){yes++;puts("Yes");}
            else puts("No");
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/sdzwyq/p/9889132.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值