zoukankan      html  css  js  c++  java
  • 【BZOJ4373】算术天才⑨与等差数列 线段树+set

    【BZOJ4373】算术天才⑨与等差数列

    Description

    算术天才⑨非常喜欢和等差数列玩耍。
    有一天,他给了你一个长度为n的序列,其中第i个数为a[i]。
    他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列。
    当然,他还会不断修改其中的某一项。
    为了不被他鄙视,你必须要快速并正确地回答完所有问题。
    注意:只有一个数的数列也是等差数列。

    Input

    第一行包含两个正整数n,m(1<=n,m<=300000),分别表示序列的长度和操作的次数。
    第二行包含n个整数,依次表示序列中的每个数a[i](0<=a[i]<=10^9)。
    接下来m行,每行一开始为一个数op,
    若op=1,则接下来两个整数x,y(1<=x<=n,0<=y<=10^9),表示把a[x]修改为y。
    若op=2,则接下来三个整数l,r,k(1<=l<=r<=n,0<=k<=10^9),表示一个询问。
    在本题中,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

    题解:最近看到这道题热度飙升,于是也来刷一发~

    对于给定的一段区间,我们如何判断排序后,它能否形成等差数列呢?换句话说,我们希望找出一些限制,使得如果一个区间是等差数列,当且仅当它满足了这些限制。可行的限制组合不唯一,这里只说我的方法。

    1.区间的max-min=(r-l)*k
    2.区间内任意两数的差%k=0
    3.区间内无重复的数

    第一个限制直接上线段树搞定。对于第二个限制,我们可以将原数组差分,然后限制就变成了差分数组中区间内的所有数%k=0,也就是区间内所有数的gcd%k=0,用线段树求区间gcd即可。

    第三个限制不太好搞,但是我们只需要维护一个pre数组,pre[i]表示上一个和v[i]相等的位置。在修改时我们可以用set来维护pre数组。然后限制就变成了区间中所有数的pre都<l,也就是区间pre的最大值<l,还是用线段树。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <set>
    #include <utility>
    #define MP(A,B) make_pair(A,B)
    #define lson x<<1
    #define rson x<<1|1
    using namespace std;
    const int maxn=300010;
    typedef long long ll;
    typedef pair<int,int> pii;
    int n,m,sum;
    int sp[maxn<<2],sm[maxn<<2],sn[maxn<<2],sg[maxn<<2],v[maxn],lp[maxn];
    set<pii> s;
    set<pii>::iterator it;
    int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int gcd(int a,int b)
    {
    	return (!b)?a:gcd(b,a%b);
    }
    void pushup(int x)
    {
    	sm[x]=max(sm[lson],sm[rson]),sn[x]=min(sn[lson],sn[rson]),sg[x]=gcd(sg[lson],sg[rson]),sp[x]=max(sp[lson],sp[rson]);
    }
    void build(int l,int r,int x)
    {
    	if(l==r)
    	{
    		sm[x]=sn[x]=v[l],sp[x]=lp[l],sg[x]=v[l]-v[l-1];
    		return ;
    	}
    	int mid=l+r>>1;
    	build(l,mid,lson),build(mid+1,r,rson);
    	pushup(x);
    }
    void updata(int l,int r,int x,int a)
    {
    	if(l==r)
    	{
    		sm[x]=sn[x]=v[l],sp[x]=lp[l],sg[x]=v[l]-v[l-1];
    		return ;
    	}
    	int mid=l+r>>1;
    	if(a<=mid)	updata(l,mid,lson,a);
    	else	updata(mid+1,r,rson,a);
    	pushup(x);
    }
    int qm(int l,int r,int x,int a,int b)
    {
    	if(a<=l&&r<=b)	return sm[x];
    	int mid=l+r>>1;
    	if(b<=mid)	return qm(l,mid,lson,a,b);
    	if(a>mid)	return qm(mid+1,r,rson,a,b);
    	return max(qm(l,mid,lson,a,b),qm(mid+1,r,rson,a,b));
    }
    int qn(int l,int r,int x,int a,int b)
    {
    	if(a<=l&&r<=b)	return sn[x];
    	int mid=l+r>>1;
    	if(b<=mid)	return qn(l,mid,lson,a,b);
    	if(a>mid)	return qn(mid+1,r,rson,a,b);
    	return min(qn(l,mid,lson,a,b),qn(mid+1,r,rson,a,b));
    }
    int qp(int l,int r,int x,int a,int b)
    {
    	if(a<=l&&r<=b)	return sp[x];
    	int mid=l+r>>1;
    	if(b<=mid)	return qp(l,mid,lson,a,b);
    	if(a>mid)	return qp(mid+1,r,rson,a,b);
    	return max(qp(l,mid,lson,a,b),qp(mid+1,r,rson,a,b));
    }
    int qg(int l,int r,int x,int a,int b)
    {
    	if(a<=l&&r<=b)	return sg[x];
    	int mid=l+r>>1;
    	if(b<=mid)	return qg(l,mid,lson,a,b);
    	if(a>mid)	return qg(mid+1,r,rson,a,b);
    	return gcd(qg(l,mid,lson,a,b),qg(mid+1,r,rson,a,b));
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i,a,b,c;
    	pii tmp;
    	for(i=1;i<=n;i++)
    	{
    		v[i]=rd(),tmp=MP(v[i],i),it=s.upper_bound(tmp);
    		if(it!=s.begin()&&(*(--it)).first==v[i])	lp[i]=(*it).second;
    		s.insert(tmp);
    	}
    	build(1,n,1);
    	for(i=1;i<=m;i++)
    	{
    		if(rd()==1)
    		{
    			a=rd()^sum,b=rd()^sum,tmp=MP(v[a],a),s.erase(tmp),it=s.upper_bound(tmp);
    			if(it!=s.end()&&(*it).first==v[a])	lp[(*it).second]=lp[a],updata(1,n,1,(*it).second);
    			v[a]=b,tmp=MP(v[a],a),it=s.upper_bound(tmp);
    			if(it!=s.end()&&(*it).first==v[a])	lp[(*it).second]=a,updata(1,n,1,(*it).second);
    			if(it!=s.begin()&&(*(--it)).first==v[a])	lp[a]=(*it).second;
    			else	lp[a]=0;
    			s.insert(tmp),updata(1,n,1,a);
    			if(a<n)	updata(1,n,1,a+1);
    		}
    		else
    		{
    			a=rd()^sum,b=rd()^sum,c=rd()^sum;
    			ll gm=qm(1,n,1,a,b),gn=qn(1,n,1,a,b);
    			if(a==b||(gm==gn&&!c)||(gm-gn==(ll)(b-a)*c&&qp(1,n,1,a,b)<a&&qg(1,n,1,a+1,b)%c==0))
    				sum++,printf("Yes
    ");
    			else	printf("No
    ");
    		}
    	}
    	return 0;
    }
    //5 3 1 3 2 5 6 2 1 5 1 1 5 4 2 1 5 1
  • 相关阅读:
    PAT (Advanced Level) Practice 1100 Mars Numbers (20分)
    PAT (Advanced Level) Practice 1107 Social Clusters (30分) (并查集)
    PAT (Advanced Level) Practice 1105 Spiral Matrix (25分)
    PAT (Advanced Level) Practice 1104 Sum of Number Segments (20分)
    PAT (Advanced Level) Practice 1111 Online Map (30分) (两次迪杰斯特拉混合)
    PAT (Advanced Level) Practice 1110 Complete Binary Tree (25分) (完全二叉树的判断+分享致命婴幼儿错误)
    PAT (Advanced Level) Practice 1109 Group Photo (25分)
    PAT (Advanced Level) Practice 1108 Finding Average (20分)
    P6225 [eJOI2019]异或橙子 树状数组 异或 位运算
    P4124 [CQOI2016]手机号码 数位DP
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7189821.html
Copyright © 2011-2022 走看看