[线段树]洛谷P5278 算术天才⑨与等差数列

题目描述

  算术天才⑨非常喜欢和等差数列玩耍。 有一天,他给了你一个长度为n的序列,其中第i个数为a[i]。 他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列。 当然,他还会不断修改其中的某一项。 为了不被他鄙视,你必须要快速并正确地回答完所有问题。 注意:只有一个数的数列也是等差数列。

输入输出格式

输入格式:

  第一行包含两个正整数n,m(1<=n,m<=300000),分别表示序列的长度和操作的次数。 第二行包含n个整数,依次表示序列中的每个数ai。 接下来m行,每行一开始为一个数op, 若op=1,则接下来两个整数x,y(1<=x<=n,0<=y<=10^9),表示把a[x]修改为y。 若op=2,则接下来三个整数l,r,k(1<=l<=r<=n,0<=k<=10^9),表示一个询问。 在本题中,x,y,l,r,k都是经过加密的,都需要异或你之前输出的Yes的个数来进行解密。

输出格式:

  输出若干行,对于每个询问,如果可以形成等差数列,那么输出Yes,否则输出No。

分析:

  题目中要求查询一段区间内的数能否构成公差为K的等差数列。由于等差数列本身不好维护,那么我们就可以去找区间内的数能构成等差数列的等价条件,再维护这些条件即可。

  通过看别人的题解,我们可以得到这些条件:

  1.这些数不相同。(废话)

  2.最大值减去最小值等于(l-r)k。(直接套公式,还是挺显然的)

  3.所有相邻两数的差的gcd都为k,即都为k的倍数。(????????)

  等差数列肯定满足以上条件,所以我们只需要来证一下它的充分性即可。

  首先,所有相邻两数的差都是k的倍数,那么我们可以知道任意两数的差都是k的倍数,因为 任意两数的差 都可以用几个 相邻两数的差 通过加减得到。

  所以,所有数与最小值的差都是k的倍数。这段区间最大值与最小值的差是(l-r)k,所以每个数与最小值做差得到的值不会超过(l-r)k那么这些差就只有0,k,2k,3k.....(l-r)k这(l-r+1)种情况。又因为这段区间有(l-r+1)个且互不相同的数,所以只有可能是把拿(l-r+1)种情况都占满了的,也就是等差数列。

  在伪证完了之后,我们来考虑如何维护这些性质。鉴于是区间查询,所以考虑线段树维护。最大值和最小值不用说,gcd只需要记录一个数和它下一个数的差,再与其它差求gcd,查询只需要查询(l,r-1)即可。至于如何确定这些数不同,我们需要用一个pre数组记录每个位置的 上一个与这个位置有相同值的位置的编号,查询时只需要查询最大的pre,只要它小于l就行。我们可以先将值离散,再把拥有相同值的位置的编号丢将进set里让它自动排序,就可以维护pre数组了。

  代码如下(自带常数大性质的我开了o2才水过,还不如去维护区间平方和和立方和碰碰运气

 

#include<set>
#include<map>
#include<cstdio>
#include<algorithm>
#define lch (id<<1)
#define rch ((id<<1)+1)
#define mid ((l+r)>>1)
#define maxn 300005
using namespace std;map<int,int >ma;
set<int>s[maxn<<1];set<int>::iterator nex,bef;
int n,m,ny,cnt,a[maxn],ori[maxn],pre[maxn];
int mxp[maxn<<3],minn[maxn<<3],maxx[maxn<<3],G[maxn<<3];
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int find(int num)
{
    int id;if(ma.count(num))return ma[num];
    id=ma[num]=++cnt;s[id].insert(0);s[id].insert(n+1);return id;
}
void fix(int l,int r,int id,int i)
{
    if(i<l||r<i)return;
    if(l==r){minn[id]=maxx[id]=a[i];mxp[id]=pre[i];G[id]=abs(a[i]-a[i+1]);return;}
    fix(l,mid,lch,i);fix(mid+1,r,rch,i);
    minn[id]=min(minn[lch],minn[rch]);
    maxx[id]=max(maxx[lch],maxx[rch]);
    mxp[id]=max(mxp[lch],mxp[rch]);G[id]=gcd(G[rch],G[lch]);
}
int q1(int l,int r,int id,int l1,int r1)
{
    if(r1<l||r<l1)return 0;
    if(l1<=l&&r<=r1)return maxx[id];
    return max(q1(l,mid,lch,l1,r1),q1(mid+1,r,rch,l1,r1));
}
int q2(int l,int r,int id,int l1,int r1)
{
    if(r1<l||r<l1)return 2000000000;
    if(l1<=l&&r<=r1)return minn[id];
    return min(q2(l,mid,lch,l1,r1),q2(mid+1,r,rch,l1,r1));
}
int ansgcd;
void q3(int l,int r,int id,int l1,int r1)
{
    if(r1<l||r<l1)return;
    if(l1<=l&&r<=r1)
    {
        if(ansgcd==-1)ansgcd=G[id];
        else ansgcd=gcd(ansgcd,G[id]);return;
    }
    q3(l,mid,lch,l1,r1);q3(mid+1,r,rch,l1,r1);
}
int q4(int l,int r,int id,int l1,int r1)
{
    if(r1<l||r<l1)return 0;
    if(l1<=l&&r<=r1)return mxp[id];
    return max(q4(l,mid,lch,l1,r1),q4(mid+1,r,rch,l1,r1));
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);s[ori[i]=find(a[i])].insert(i);
        bef=s[ori[i]].find(i);bef--;pre[i]=*bef;
        fix(1,n,1,i);if(i>1)fix(1,n,1,i-1);
    }
    for(int t=1,ord,x,l,r,k;t<=m;t++)
    {
        scanf("%d",&ord);
        if(ord==1)
        {
            scanf("%d%d",&x,&k);x^=ny;k^=ny;
            nex=s[ori[x]].find(x);nex++;
            if(*nex!=n+1){pre[*nex]=pre[x];fix(1,n,1,*nex);}
            s[ori[x]].erase(x);
            s[ori[x]=find(a[x]=k)].insert(x);
            nex=s[ori[x]].find(x);nex++;
            pre[x]=pre[*nex];
            if(*nex!=n+1){pre[*nex]=x;fix(1,n,1,*nex);}
            fix(1,n,1,x);
            if(x>1)fix(1,n,1,x-1);
        }
        if(ord==2)
        {
           scanf("%d%d%d",&l,&r,&k);l^=ny;r^=ny;k^=ny;
            if(l==r){printf("Yes\n"),ny++;continue;}
            int mx=q1(1,n,1,l,r),mn=q2(1,n,1,l,r),p=q4(1,n,1,l,r),g;
            ansgcd=-1;q3(1,n,1,l,r-1);g=ansgcd;
            if(k==0&&mx-mn==0){printf("Yes\n"),ny++;continue;}
            if(k==0&&mx-mn!=0){printf("No\n");continue;}
            if(g%k==0&&mx-mn==(r-l)*k&&p<l)printf("Yes\n"),ny++;
            else printf("No\n");
        }
    }
}

 

posted @ 2019-07-23 15:51  散樗  阅读(313)  评论(0编辑  收藏  举报