BZOJ4373 算术天才⑨与等差数列(线段树)

  看上去很难维护,考虑找一些必要条件。首先显然最大值-最小值=k*(r-l)。然后区间内的数需要模k同余。最后区间内的数两两不同(k=0除外)。冷静一下可以发现这些条件组合起来就是充分的了。

  考虑怎么维护。最大值最小值非常简单。模k同余相当于区间内相邻两数的差都是k的倍数,可以维护差分数组的gcd。两两不同相当于区间内没有出现次数>1的数,对每个数用set维护上一个和他相同的数的位置,线段树维护,区间查询max,如果<l则说明不存在。

  开始判断是否不同的写出锅了,结果删掉竟然过了23333

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
#include<set>
#include<cassert> 
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 300010
#define ll long long
int n,m,a[N],b[N],lst,cnt;
map<int,int> f;
set<int> pre[N<<1];
int L[N<<2],R[N<<2],mn[N<<2],mx[N<<2],GCD[N<<2],last[N<<2];
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
void up(int k)
{
    mn[k]=min(mn[k<<1],mn[k<<1|1]);
    mx[k]=max(mx[k<<1],mx[k<<1|1]);
    last[k]=max(last[k<<1],last[k<<1|1]);
    GCD[k]=gcd(GCD[k<<1],GCD[k<<1|1]);
}
void build(int k,int l,int r)
{
    L[k]=l,R[k]=r;
    if (l==r) 
    {
        mn[k]=mx[k]=a[l];GCD[k]=b[l];
        last[k]=*(--pre[f[a[l]]].find(l));
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    up(k);
}
void modify(int k,int p,int x,int op)
{
    if (L[k]==R[k])
    {
        if (op==0) mn[k]=mx[k]=x;
        else if (op==1) GCD[k]=x;
        else last[k]=x;
        return;
    }
    int mid=L[k]+R[k]>>1;
    if (p<=mid) modify(k<<1,p,x,op);
    else modify(k<<1|1,p,x,op);
    up(k);
}
int qmax(int k,int l,int r)
{
    if (L[k]==l&&R[k]==r) return mx[k];
    int mid=L[k]+R[k]>>1;
    if (r<=mid) return qmax(k<<1,l,r);
    else if (l>mid) return qmax(k<<1|1,l,r);
    else return max(qmax(k<<1,l,mid),qmax(k<<1|1,mid+1,r)); 
}
int qmin(int k,int l,int r)
{
    if (L[k]==l&&R[k]==r) return mn[k];
    int mid=L[k]+R[k]>>1;
    if (r<=mid) return qmin(k<<1,l,r);
    else if (l>mid) return qmin(k<<1|1,l,r);
    else return min(qmin(k<<1,l,mid),qmin(k<<1|1,mid+1,r)); 
}
int qgcd(int k,int l,int r)
{
    if (L[k]==l&&R[k]==r) return GCD[k];
    int mid=L[k]+R[k]>>1;
    if (r<=mid) return qgcd(k<<1,l,r);
    else if (l>mid) return qgcd(k<<1|1,l,r);
    else return gcd(qgcd(k<<1,l,mid),qgcd(k<<1|1,mid+1,r)); 
}
int qlast(int k,int l,int r)
{
    if (L[k]==l&&R[k]==r) return last[k];
    int mid=L[k]+R[k]>>1;
    if (r<=mid) return qlast(k<<1,l,r);
    else if (l>mid) return qlast(k<<1|1,l,r);
    else return max(qlast(k<<1,l,mid),qlast(k<<1|1,mid+1,r)); 
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    freopen("bzoj4373.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read(),m=read();
    for (int i=1;i<=n;i++)
    {
        a[i]=read(),b[i]=abs(a[i]-a[i-1]);
        if (f.find(a[i])==f.end()) f[a[i]]=++cnt,pre[cnt].insert(0);
        pre[f[a[i]]].insert(i);
    }
    build(1,1,n);
    while (m--)
    {
        int op=read();
        if (op==1)
        {
            int p=read()^lst,x=read()^lst;
            int t=f[a[p]];set<int>::iterator it=++pre[t].find(p);
            if (it!=pre[t].end()) modify(1,*it,*(--pre[t].find(p)),2);
            pre[t].erase(p);
            a[p]=x;modify(1,p,x,0);
            modify(1,p,abs(a[p]-a[p-1]),1);
            if (p<=n) modify(1,p+1,abs(a[p+1]-a[p]),1);
            if (f.find(a[p])==f.end()) f[a[p]]=++cnt,pre[cnt].insert(0);
            t=f[a[p]];it=pre[t].lower_bound(p);
            if (it!=pre[t].end()) modify(1,*it,p,2);
            it--;modify(1,p,*it,2);pre[t].insert(p);
        }
        else
        {
            int l=read()^lst,r=read()^lst,d=read()^lst;
            if (qmax(1,l,r)-qmin(1,l,r)==1ll*d*(r-l)&&(d==0||l==r||((qgcd(1,l+1,r)%d==0)&&qlast(1,l,r)<l))) lst++,printf("Yes\n");
            else printf("No\n");
        }
    }
    return 0;
}

 

posted @ 2018-10-28 20:23  Gloid  阅读(220)  评论(0编辑  收藏  举报