zoukankan      html  css  js  c++  java
  • [线段树]洛谷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
    "),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
    "),ny++;continue;}
                if(k==0&&mx-mn!=0){printf("No
    ");continue;}
                if(g%k==0&&mx-mn==(r-l)*k&&p<l)printf("Yes
    "),ny++;
                else printf("No
    ");
            }
        }
    }
  • 相关阅读:
    Python动态展示遗传算法求解TSP旅行商问题
    MOEAD算法中均匀权向量的实现---Python
    HDU 5294 多校第一场1007题 最短路+最小割
    POJ 3261 Milk Patterns sa+二分
    HDU 4292 FOOD 2012 ACM/ICPC Asia Regional Chengdu Online
    CodeForces 201A Clear Symmetry
    POJ 1679 The Unique MST 确定MST是否唯一
    POJ 3268 Silver Cow Party 最短路 基础题
    POJ 2139 SIx Degrees of Cowvin Bacon 最短路 水題
    POJ2229 Sumsets 基礎DP
  • 原文地址:https://www.cnblogs.com/firecrazy/p/11228581.html
Copyright © 2011-2022 走看看