4373: 算术天才⑨与等差数列

18 篇文章 0 订阅
3 篇文章 0 订阅
首先特判掉k=0和l=r的情况,那么剩下来的情况要成立必满足三个条件:
①区间内max-min=k*区间长,用线段树维护max和min就好了。
②区间排序后差分,gcd==k。gcd也可以用线段树维护,即差分后,gcd=gcd(左儿子gcd,右儿子gcd)(注意gcd=0是须特判)。
③区间内没有重复的值。对于每个权值开一个set,用于查询每个点的右边第一次出现和它相等的值的下标。线段树维护这些下标的min,如果查询时min大于r说明符合条件。
然而烧了一天也没搞出这题来。最后,**哥告诉我:“你被卡常了。放弃吧。”
我简直是来搞笑的。
代码:
#pragma GCC optimize("O2")
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define G getchar()
#define LL long long
#define pll pair<int,int>
#define mkp make_pair
#define X first
#define Y second
const int N=300005;
int n,a[N],pre[N],nxt[N],ans;
set<int>st[N<<1];map<int,int>mp;int id;
int Max[N<<2],Min[N<<2],Gcd[N<<2],Flg[N<<2],Nxt[N<<2];
int MAX,MIN,GCD,NXT;
inline void read(int &x){
	char ch=G;//int f=1;
	for(;ch>57||ch<48;ch=G);//if(ch==45)f=-1;
	for(x=0;ch>=48&&ch<=57;ch=G)x=x*10+ch-48;
	//x*=f;
}
void modify2(int x,int l,int r,int num){
	if(l==r){
		Nxt[num]=nxt[l];return;
	}
	int mid=l+r>>1;
	if(x>mid)modify2(x,mid+1,r,num<<1|1);
	else modify2(x,l,mid,num<<1);
	Nxt[num]=min(Nxt[num<<1],Nxt[num<<1|1]);
}
inline void ins(int i){
	set<int>::iterator ii;
	if(mp.insert(mkp(a[i],id)).Y){
		st[id].insert(nxt[i]=n+1);st[id].insert(pre[i]=0);
		st[id++].insert(i);
	}
	else{
		ii=st[mp[a[i]]].insert(i).X;
		++ii;
		if((nxt[i]=*ii)<=n)pre[nxt[i]]=i;
		--ii;--ii;
		if(pre[i]=*ii){nxt[pre[i]]=i;modify2(pre[i],1,n,1);}
	}
}
inline void del(int i){
	int x=mp[a[i]];
	set<int>::iterator ii=st[x].lower_bound(i);
	if(nxt[i]<=n)pre[nxt[i]]=pre[i];
	if(pre[i]){nxt[pre[i]]=nxt[i];modify2(pre[i],1,n,1);}
	st[x].erase(ii);
}
int gcd(int x,int y){
	if(!x)return y;
	if(!y)return x;
	if(x%y==0)return y;
	return gcd(y,x%y);
}
inline void up(int num){
	Max[num]=max(Max[num<<1],Max[num<<1|1]);
	Min[num]=min(Min[num<<1],Min[num<<1|1]);
	Flg[num]=Flg[num<<1]==Flg[num<<1|1]?Flg[num<<1]:-1;
	Nxt[num]=min(Nxt[num<<1],Nxt[num<<1|1]);
}
inline void up2(int num){
	Gcd[num]=gcd(Gcd[num<<1],Gcd[num<<1|1]);
}
void build(int l,int r,int num){
	if(l==r){
		Max[num]=Min[num]=Flg[num]=a[l];
		Nxt[num]=nxt[l];return;
	}
	int mid=l+r>>1;
	build(l,mid,num<<1);build(mid+1,r,num<<1|1);
	up(num);
}
void build2(int l,int r,int num){
	if(l==r){
		Gcd[num]=abs(a[l]-a[l+1]);
		return;
	}
	int mid=l+r>>1;
	build2(l,mid,num<<1);build2(mid+1,r,num<<1|1);
	up2(num);
}
void modify(int x,int y,int l,int r,int num){
	if(l==r){
		del(l);
		Max[num]=Min[num]=Flg[num]=a[l]=y;
		ins(l);Nxt[num]=nxt[l];return;
	}
	int mid=l+r>>1;
	if(x<=mid)modify(x,y,l,mid,num<<1);
	else modify(x,y,mid+1,r,num<<1|1);
	up(num);
}
void modify2(int x,int y,int l,int r,int num){
	if(l==r){
		Gcd[num]=y;return;
	}
	int mid=l+r>>1;
	if(x<=mid)modify2(x,y,l,mid,num<<1);
	else modify2(x,y,mid+1,r,num<<1|1);
	up2(num);
}
int query1(int L,int R,int l,int r,int num){
	if(L<=l&&r<=R)return Flg[num];
	int mid=l+r>>1;
	if(R<=mid)return query1(L,R,l,mid,num<<1);
	if(L>mid)return query1(L,R,mid+1,r,num<<1|1);
	int tmp=query1(L,R,l,mid,num<<1);
	return tmp==query1(L,R,mid+1,r,num<<1|1)?tmp:-1;
}
int query2(int L,int R,int l,int r,int num){
	if(L<=l&&r<=R){
		MAX=max(MAX,Max[num]);
		MIN=min(MIN,Min[num]);
		NXT=min(NXT,Nxt[num]);
		return Gcd[num];
	}
	int mid=l+r>>1;
	if(R<=mid)return query2(L,R,l,mid,num<<1);
	if(L>mid)return query2(L,R,mid+1,r,num<<1|1);
	return gcd(query2(L,R,l,mid,num<<1),query2(L,R,mid+1,r,num<<1|1));
}
void query(int L,int R,int l,int r,int num){
	if(L<=l&&r<=R){
		MAX=max(MAX,Max[num]);
		MIN=min(MIN,Min[num]);
		NXT=min(NXT,Nxt[num]);
		return;
	}
	int mid=l+r>>1;
	if(L<=mid)query(L,R,l,mid,num<<1);
	if(R>mid)query(L,R,mid+1,r,num<<1|1);
}
int main(){
//	freopen("r.in","r",stdin);
//	freopen("w.out","w",stdout);
	int Q,i,o,x,y,k;
	read(n);read(Q);
	rep(i,1,n){
		read(a[i]);
		if(n!=1)ins(i);
	}
	if(n!=1)build(1,n,1),build2(1,n-1,1);
	while(Q--){
		read(o);read(x);read(y);x^=ans;y^=ans;
		if(o==1){
			if(n==1)continue;
			if(x<n)modify2(x,abs(a[x+1]-y),1,n-1,1);
			if(x>1)modify2(x-1,abs(a[x-1]-y),1,n-1,1);
			modify(x,y,1,n,1);
		}
		else{
			read(k);k^=ans;
			if(x==y){
				++ans,puts("Yes");continue;
			}
			if(!k){
				if(query1(x,y,1,n,1)>=0)
					++ans,puts("Yes");
				else
					puts("No");
				continue;
			}
			MAX=0,MIN=NXT=n+1;
			query(x,y,1,n,1);
			GCD=query2(x,y-1,1,n-1,1);
			if(GCD==k&&MAX-MIN==k*(y-x)&&NXT>y)
				++ans,puts("Yes");
			else puts("No");
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值