您的位置:首页 > 其它

【线段树】BZOJ4373算术天才与等差数列

2016-03-02 00:00 309 查看
传送门

Description

给定一个长度为 n 的序列,其中第 i 个数为 ai。

有 m 次操作,每次要么修改其中的某一项,要么给出询问l; r; k,问区间 [l; r] 内的数从小到大排序后能否形成公差为 k 的等差数列。

Input

第一行包含两个正整数n,m(1<=n,m<=300000),分别表示序列的长度和操作的次数。

第二行包含n个整数,依次表示序列中的每个数ai(0<=ai<=109)。

接下来m行,每行一开始为一个数op,

若op=1,则接下来两个整数x,y(1<=x<=n,0<=y<=109),表示把ax修改为y。

若op=2,则接下来三个整数l,r,k(1<=l<=r<=n,0<=k<=109),表示一个询问。

在本题中,x,y,l,r,k都是经过加密的,都需要异或你之前输出的Yes的个数来进行解密。

Output

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

Sample Input

5 3

1 3 2 5 6

2 1 5 1

1 5 4

2 1 5 1

Sample Output

No

Yes

条件一:这一区间的最大值与最小值的差满足等差数列的公式(ai−aj=d∗(i−j))。

条件二:这一区间的所有数模k的值相同。

条件二相对于条件一麻烦得多,于是考虑相邻的两个数的差。如果差x模k的值为0,则满足。

这样就可以用线段树水过辣。

简单滴解释一下下面线段树中的标记含义。

maxv:区间最大值。minv:区间最小值。

l:左端点的值。r:右端点的值。

k:区间关于k成等差数列。

可能在写的过程中up函数比较难写。

注意gcd(a,b)中不能模0。

据说可以用等差数列的和、各项平方的和水过 2333

#include <iostream>
#include <cstdio>
#include <algorithm>
#define MAXN 300005
using namespace std;

int n, m, num[MAXN];

inline int id(int x,int y){return (x+y)|(x!=y);}

int gcd(int a,int b)
{
if(!a)return b;
if(!b)return a;
return gcd(b,a%b);
}

struct node
{
int maxv, minv, l, r, k;
};

struct SGE
{
node t[MAXN<<1];
inline void up(node &a,node &b,node &c)
{
a.maxv=max(b.maxv,c.maxv), a.minv=min(b.minv,c.minv);
a.l=b.l, a.r=c.r;
a.k=gcd(gcd(b.k,c.k),abs(c.l-b.r));
}
void build(int code,int l,int r)
{
if(l==r)
{
t[code].maxv=t[code].minv=t[code].l=t[code].r=num[l];
return;
}
int mid=(l+r)>>1;
int lc=id(l,mid), rc=id(mid+1,r);
build(lc,l,mid), build(rc,mid+1,r);
up(t[code],t[lc],t[rc]);
}
node query(int code,int l,int r,int ql,int qr)
{
if(l==ql&&r==qr)return t[code];
int mid=(l+r)>>1;
if(qr<=mid)return query(id(l,mid),l,mid,ql,qr);
if(mid<ql)return query(id(mid+1,qr),mid+1,r,ql,qr);
int lc=id(l,mid), rc=id(mid+1,r);
node ans, ans1, ans2;
ans1=query(lc,l,mid,ql,mid), ans2=query(rc,mid+1,r,mid+1,qr);
up(ans,ans1,ans2);
return ans;
}
void change(int code,int l,int r,int pos,int d)
{
if(l==r)
{
t[code].maxv=t[code].minv=t[code].l=t[code].r=d;
return;
}
int mid=(l+r)>>1;
int lc=id(l,mid), rc=id(mid+1,r);
if(pos<=mid)change(lc,l,mid,pos,d);
else change(rc,mid+1,r,pos,d);
up(t[code],t[lc],t[rc]);
}
}sge;

bool solve(int l,int r,int k)
{
if(l==r)return 1;
node ans=sge.query(id(1,n),1,n,l,r);
if(ans.k==k&&ans.maxv-ans.minv==k*(r-l))return 1;
return 0;
}

int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)scanf("%d",&num[i]);
sge.build(id(1,n),1,n);
int key=0, f, l, r, x;
while(m--)
{
scanf("%d%d%d",&f,&l,&r);
l^=key, r^=key;
if(f==1)
sge.change(id(1,n),1,n,l,r);
else
{
scanf("%d",&x);
x^=key;
if(solve(l,r,x))
{
++key;
puts("Yes");
}
else puts("No");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树 BZOJ4373