bzoj4373 算术天才⑨与等差数列——线段树+set

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4373

一个区间有以 k 为公差的数列,有3个条件:

1.区间 mx - mn = (r-l) * k;

2.差分数组的 gcd 是 k 的倍数;

3.没有重复出现的数;

其中1,2都可以用线段树维护,3用 set 维护每个数上一个出现的位置即可;

模仿TJ写的:https://blog.csdn.net/neither_nor/article/details/52461940

对 set 更熟悉了,细节还蛮多的。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#include<map>
using namespace std;
int const maxn=3e5+5;
int n,m,a[maxn],key,tot,pre[maxn];
map<int,int>h;
set<int>s[maxn<<1];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int ab(int x){return x>0?x:-x;}
struct N{
    int mx,mn,fro,g;
    friend N operator + (N x,N y)
    {
        N ret;
        ret.mx=max(x.mx,y.mx);
        ret.mn=min(x.mn,y.mn);
        ret.fro=max(x.fro,y.fro);
        ret.g=gcd(x.g,y.g);
        return ret;//!
    }
}t[maxn<<2];
void build(int x,int l,int r)
{
    if(l==r)
    {
        t[x].mn=t[x].mx=a[l]; t[x].g=ab(a[l+1]-a[l]);
        t[x].fro=pre[l]; return;
    }
    int mid=((l+r)>>1);
    build(x<<1,l,mid); build(x<<1|1,mid+1,r);
    t[x]=t[x<<1]+t[x<<1|1];
}
void update(int x,int l,int r,int p)
{
    if(l==r)
    {
        t[x].mn=t[x].mx=a[l]; t[x].g=ab(a[l+1]-a[l]);
        t[x].fro=pre[l]; return;
    }
    int mid=((l+r)>>1);
    if(p<=mid)update(x<<1,l,mid,p);
    else update(x<<1|1,mid+1,r,p);
    t[x]=t[x<<1]+t[x<<1|1];
}
N query(int x,int l,int r,int L,int R)
{
    if(l>=L&&r<=R)return t[x];
    int mid=((l+r)>>1);
    if(mid<L)return query(x<<1|1,mid+1,r,L,R);
    else if(mid>=R)return query(x<<1,l,mid,L,R);
    else return query(x<<1,l,mid,L,R)+query(x<<1|1,mid+1,r,L,R);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if(!h[a[i]])
        {
            h[a[i]]=++tot;
            s[tot].insert(0);
            s[tot].insert(n+1);
        }
        int tmp=h[a[i]];
        s[tmp].insert(i);
        pre[i]=*--(s[tmp].insert(i).first);//
    }
    a[n+1]=a[n];//!
    build(1,1,n);
    for(int i=1,op,x,y,l,r,k;i<=m;i++)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d",&x,&y);
            x^=key; y^=key;
            int tmp,nxt,pr;
            tmp=h[a[x]];
            nxt=*s[tmp].upper_bound(x);
            if(nxt!=n+1)
            {
                pre[nxt]=pre[x];
                update(1,1,n,nxt);
            }
            s[tmp].erase(x);
            
            if(!h[y])//
            {
                h[y]=++tot;
                s[tot].insert(0);
                s[tot].insert(n+1);
            }
            tmp=h[y];
            s[tmp].insert(x);
            nxt=*s[tmp].upper_bound(x);
            pre[x]=*--s[tmp].lower_bound(x);
            if(nxt!=n+1)
            {
                pre[nxt]=x;
                update(1,1,n,nxt);
            }
            a[x]=y;
            update(1,1,n,x);
            if(x!=1)update(1,1,n,x-1);//
        }
        if(op==2)
        {
            scanf("%d%d%d",&l,&r,&k);
            l^=key; r^=key; k^=key;
            if(l==r){key++; printf("Yes\n"); continue;}
            N tmpp=query(1,1,n,l,r-1);//
            N tmp=tmpp+query(1,1,n,r,r);//
            if(k==0)
            {
                if(tmp.mx==tmp.mn)key++,printf("Yes\n");
                else printf("No\n");
                continue;
            }
            if(tmp.fro<l && tmp.mx==k*(r-l)+tmp.mn && tmpp.g%k==0)//tmpp!
                key++,printf("Yes\n");
            else printf("No\n");
        }
    }
    return 0;
}

 

posted @ 2018-07-11 21:11  Zinn  阅读(168)  评论(0编辑  收藏  举报