设$pre[i]$表示第$i$个数上一次出现的位置,$d[i]=abs(a[i]-a[i+1])$。

用线段树维护区间内$a$的最小值、最大值,$pre$的最大值以及$d$的$\gcd$。

对于询问$l\ r\ k$,首先特判掉$l=r$或者$k=0$的情况。

然后求出区间最小值和最大值、以及$pre$的最大值,判断最值是否合法以及$pre$是否都小于$l$。

如果都满足,那么继续查询$[l,r-1]$里所有$d$的$\gcd$,如果$\gcd$是$k$的倍数,那么就可行。

时间复杂度$O(n\log n)$。

#include<cstdio>
#include<cstdlib>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int N=300010,M=1050000;
int n,m,cnt,i,op,x,y,z,a[N],b[N],c[N],d[N],K;
int vmi[M],vma[M],vp[M],vd[M],mi,ma,flag,g;
map<int,int>id;
set<int>T[N<<1];
set<int>::iterator pre,nxt;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline int abs(int x){return x>0?x:-x;}
inline int gcd(int a,int b){
if(!a)return b;
if(!b)return a;
return __gcd(a,b);
}
inline int getid(int x){
int&t=id[x];
if(t)return t;
t=++cnt;
T[t].insert(0),T[t].insert(n+1);
return t;
}
void build(int x,int a,int b){
if(a==b){
vmi[x]=vma[x]=::a[a];
vp[x]=c[a];
vd[x]=d[a];
return;
}
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b);
vmi[x]=min(vmi[x<<1],vmi[x<<1|1]);
vma[x]=max(vma[x<<1],vma[x<<1|1]);
vp[x]=max(vp[x<<1],vp[x<<1|1]);
vd[x]=gcd(vd[x<<1],vd[x<<1|1]);
}
void changep(int x,int a,int b,int c,int p){
if(a==b){
vp[x]=p;
return;
}
int mid=(a+b)>>1;
if(c<=mid)changep(x<<1,a,mid,c,p);else changep(x<<1|1,mid+1,b,c,p);
vp[x]=max(vp[x<<1],vp[x<<1|1]);
}
void change(int x,int a,int b,int c,int v,int p){
if(a==b){
vmi[x]=vma[x]=v;
vp[x]=p;
return;
}
int mid=(a+b)>>1;
if(c<=mid)change(x<<1,a,mid,c,v,p);else change(x<<1|1,mid+1,b,c,v,p);
vmi[x]=min(vmi[x<<1],vmi[x<<1|1]);
vma[x]=max(vma[x<<1],vma[x<<1|1]);
vp[x]=max(vp[x<<1],vp[x<<1|1]);
}
void changed(int x,int a,int b,int c,int p){
if(a==b){
vd[x]=p;
return;
}
int mid=(a+b)>>1;
if(c<=mid)changed(x<<1,a,mid,c,p);else changed(x<<1|1,mid+1,b,c,p);
vd[x]=gcd(vd[x<<1],vd[x<<1|1]);
}
void ask(int x,int a,int b,int c,int d){
if(c<=a&&b<=d){
mi=min(mi,vmi[x]);
ma=max(ma,vma[x]);
if(vp[x]>=c)flag=1;
return;
}
int mid=(a+b)>>1;
if(c<=mid)ask(x<<1,a,mid,c,d);
if(d>mid)ask(x<<1|1,mid+1,b,c,d);
}
void askd(int x,int a,int b,int c,int d){
if(c<=a&&b<=d){
g=gcd(g,vd[x]);
return;
}
int mid=(a+b)>>1;
if(c<=mid)askd(x<<1,a,mid,c,d);
if(d>mid)askd(x<<1|1,mid+1,b,c,d);
}
inline bool query(int x,int y,int z){
if(x==y)return 1;
mi=1000000000,ma=flag=g=0;
ask(1,1,n,x,y);
if(!z)return mi==ma;
if(flag)return 0;
if(1LL*(y-x)*z+mi!=ma)return 0;
askd(1,1,n,x,y-1);
return g%z==0;
}
int main(){
read(n),read(m);
for(i=1;i<=n;i++){
read(a[i]);
T[b[i]=getid(a[i])].insert(i);
pre=T[b[i]].find(i);
c[i]=*(--pre);
}
for(i=1;i<n;i++)d[i]=abs(a[i]-a[i+1]);
build(1,1,n);
while(m--){
read(op),read(x),read(y);x^=K,y^=K;
if(op==1){
pre=nxt=T[b[x]].find(x);
pre--,nxt++;
if(*nxt<n)changep(1,1,n,*nxt,*pre);
T[b[x]].erase(x);
b[x]=getid(y);
T[b[x]].insert(x);
pre=nxt=T[b[x]].find(x);
pre--,nxt++;
if(*nxt<n)changep(1,1,n,*nxt,x);
change(1,1,n,x,a[x]=y,*pre);
if(x>1)changed(1,1,n,x-1,abs(a[x-1]-y));
if(x<n)changed(1,1,n,x,abs(y-a[x+1]));
}else{
read(z);
if(query(x,y,z^K))K++,puts("Yes");else puts("No");
}
}
return 0;
}

  

BZOJ4373 : 算术天才⑨与等差数列的更多相关文章

  1. BZOJ4373 算术天才⑨与等差数列 【线段树】*

    BZOJ4373 算术天才⑨与等差数列 Description 算术天才⑨非常喜欢和等差数列玩耍. 有一天,他给了你一个长度为n的序列,其中第i个数为a[i]. 他想考考你,每次他会给出询问l,r,k ...

  2. 【线段树 集合hash】bzoj4373: 算术天才⑨与等差数列

    hash大法好(@ARZhu):大数相乘及时取模真的是件麻烦事情 Description 算术天才⑨非常喜欢和等差数列玩耍.有一天,他给了你一个长度为n的序列,其中第i个数为a[i].他想考考你,每次 ...

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

    [l,r]中所有数排序后能构成公差为k的等差数列,当且仅当: 1.区间中最大数-最小数=k*(r-l) 2.k能整除区间中任意两个相邻数之差,即k | gcd(a[l+1]-a[l],a[l+2]-a ...

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

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

  5. BZOJ4373 算术天才与等差数列 题解

    题目大意: 一个长度为n的序列,其中第i个数为a[i].修改一个点的值询问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列. 思路: 1.一段区间符合要求满足:(1)区间中的max-min ...

  6. BZOJ4373: 算术天才⑨与等差数列(线段树 hash?)

    题意 题目链接 Sol 正经做法不会,听lxl讲了一种很神奇的方法 我们考虑如果满足条件,那么需要具备什么条件 设mx为询问区间最大值,mn为询问区间最小值 mx - mn = (r - l) * k ...

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

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4373 一个区间有以 k 为公差的数列,有3个条件: 1.区间 mx - mn = (r-l) ...

  8. 【BZOJ4373】算术天才⑨与等差数列 线段树+set

    [BZOJ4373]算术天才⑨与等差数列 Description 算术天才⑨非常喜欢和等差数列玩耍.有一天,他给了你一个长度为n的序列,其中第i个数为a[i].他想考考你,每次他会给出询问l,r,k, ...

  9. 【BZOJ4373】算术天才⑨与等差数列 [线段树]

    算术天才⑨与等差数列 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 算术天才⑨非常喜欢和等 ...

随机推荐

  1. poj2632 模拟

    Crashing Robots Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8388   Accepted: 3631 D ...

  2. urllib2加入header及解决中文乱码问题

    def main(): url = "http://www.douban.com" #伪装桌面浏览器 headers = {'User-Agent':'Mozilla/5.0 (W ...

  3. qcow2文件压缩

    qemu-img convert -O qcow2 /path/old.img.qcow2 /path/new.img.qcow2 转自:https://havee.me/linux/2011-09/ ...

  4. django migration使用指南

    转自: https://docs.djangoproject.com/en/1.8/topics/migrations/

  5. ASP.NET MVC 的URL路由介绍

    在这个教程中,向你介绍每个ASP.NET MVC一个重要的特点叫做URL路由.URL路由模块是负责映射从浏览器请求到特定的控制器动作. 在教程的第一部分,你将学习标准路由表如何映射到控制器的动作.在教 ...

  6. 《ASP.NET1200例》统计网站访问量源代码

    void Application_Start(object sender, EventArgs e)     {        //在应用程序启动时运行的代码        int count=0;  ...

  7. 那些臭名昭著的sql

    两个或多个表关联,没写where条件,大量的笛卡尔值,严重时会导致数据库有问题. select * from a, b left join c on b.id = c.id left join d o ...

  8. Android 中PendingIntent---附带解决AlarmManager重复加入问题

    最近在程序中使用到了notification功能,自然,就涉及到了PendingIntent,下面总结下. 1 什么是PendingIntent A description of an Intent ...

  9. Java for LeetCode 174 Dungeon Game

    The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. ...

  10. Java for LeetCode 140 Word Break II

    Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each ...