zoukankan      html  css  js  c++  java
  • 【洛谷5278】算术天才⑨与等差数列(线段树)

    点此看题面

    • 给定一个长度为(n)的序列。
    • (q)次操作,分为两种:单点修改;询问区间([l,r])内的数是否能重排为一个公差为(d)的等差数列。
    • (n,mle3 imes10^5),强制在线

    等差数列的充要条件

    考虑能重排为一个公差为(d)的等差数列的充要条件:

    • 极差为((r-l) imes d) 这只需要维护区间最大值和区间最小值。
    • 数不重复。 这只要记录每个数上一次出现的位置(pre_i),求出区间(pre)最大值判断是否小于(l)。要求(pre_i)只要对于每种值开一个(set)维护。
    • 相邻两数之差的(gcd)(d)的倍数。 另开一棵线段树存储相邻两数之差,并维护区间(gcd)即可。

    注意(d=0)要特判,此时相当于是判断区间内的所有数是否都一样,这也就意味着极差为(0)

    代码:(O(nlog^2n))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 300000
    using namespace std;
    int n,m,a[N+5];I int gcd(CI x,CI y) {return y?gcd(y,x%y):x;}
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	char oc,FI[FS],*FA=FI,*FB=FI;
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    }using namespace FastIO;
    struct Data
    {
    	int Mn,Mx,P;I Data(CI a=0,CI b=0,CI c=0):Mn(a),Mx(b),P(c){}
    	I Data operator + (Con Data& o) Con {return Data(min(Mn,o.Mn),max(Mx,o.Mx),max(P,o.P));}
    };
    class SegmentTree1
    {
    	private:
    		#define PT CI l=1,CI r=n,CI rt=1
    		#define LT l,mid,rt<<1
    		#define RT mid+1,r,rt<<1|1
    		#define PU(x) (V[x]=V[x<<1]+V[x<<1|1])
    		Data V[N<<2];
    	public:
    		I void U(CI x,CI v,CI p,PT)//单点修改值和pre
    		{
    			if(l==r) return (void)(V[rt]=Data(v,v,p));RI mid=l+r>>1;x<=mid?U(x,v,p,LT):U(x,v,p,RT),PU(rt);
    		}
    		I Data Q(CI L,CI R,PT)//询问区间最大最小值、pre最大值
    		{
    			if(L<=l&&r<=R) return V[rt];RI mid=l+r>>1;if(R<=mid) return Q(L,R,LT);
    			if(L>mid) return Q(L,R,RT);return Q(L,mid,LT)+Q(mid+1,R,RT);
    		}
    }S1;
    class SegmentTree2
    {
    	private:
    		#define PT CI l=1,CI r=n-1,CI rt=1
    		#define LT l,mid,rt<<1
    		#define RT mid+1,r,rt<<1|1
    		#define PU(x) (D[x]=gcd(D[x<<1],D[x<<1|1]))
    		int D[N<<2];
    	public:
    		I void U(CI x,CI d,PT)//单点修改差值
    		{
    			if(l==r) return (void)(D[rt]=d);RI mid=l+r>>1;x<=mid?U(x,d,LT):U(x,d,RT),PU(rt);
    		}
    		I int Q(CI L,CI R,PT)//询问区间差值gcd
    		{
    			if(L<=l&&r<=R) return D[rt];RI mid=l+r>>1;if(R<=mid) return Q(L,R,LT);
    			if(L>mid) return Q(L,R,RT);return gcd(Q(L,mid,LT),Q(mid+1,R,RT));
    		}
    }S2;
    namespace Pre//pre相关
    {
    	int cnt;map<int,int> id;I int ID(CI x) {return ~x?(id.count(x)?id[x]:id[x]=++cnt):0;}//离散化
    	set<int> S[2*N+5];I void Ins(CI x,CI v)//加入下标为x的元素v
    	{
    		RI o=ID(v);S1.U(x,v,S[o].empty()?0:*--S[o].end()),S[o].insert(x);//判断之前是否出现过求出前驱
    	}
    	I void U(CI x,CI a,CI b)//把下标为x的元素由a改为b
    	{
    		#define pre(S,x) (S.lower_bound(x)!=S.begin()?*--S.lower_bound(x):0)//前驱
    		#define nxt(S,x) (S.upper_bound(x)!=S.end()?*S.upper_bound(x):0)//后继
    		RI o=ID(a),p=pre(S[o],x),q=nxt(S[o],x);S[o].erase(x),q&&(S1.U(q,a,p),0);//从原set中删去,修改后继的前驱
    		o=ID(b),p=pre(S[o],x),q=nxt(S[o],x),q&&(S1.U(q,b,x),0),S[o].insert(x),S1.U(x,b,p);//加入新set,更新后继及当前点的前驱
    	}
    }
    I bool Check(CI l,CI r,CI d)//检验[l,r]是否能重排为一个公差为d的等差数列
    {
    	if(l==r) return 1;Data t=S1.Q(l,r);RI g=S2.Q(l,r-1);return t.Mx-t.Mn==1LL*d*(r-l)&&(!d||t.P<l&&!(g%d));//极差为(r-l)*d;不重复;相邻差值gcd为d倍数(特判d=0)
    }
    int main()
    {
    	RI Qt,i;for(read(n,Qt),i=1;i<=n;++i) read(a[i]),Pre::Ins(i,a[i]),i^1&&(S2.U(i-1,abs(a[i]-a[i-1])),0);//初始化
    	RI op,x,y,z,t=0;W(Qt--) read(op,x,y),x^=t,y^=t,
    		op==1?(Pre::U(x,a[x],y),a[x]=y,x^n&&(S2.U(x,abs(a[x+1]-a[x])),0),x^1&&(S2.U(x-1,abs(a[x]-a[x-1])),0))//更新值;更新差值
    		:(read(z),z^=t,puts(Check(x,y,z)?(++t,"Yes"):"No"));//询问
    	return 0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    时间复杂度计算
    SQL Server2012编程入门经典(第四版) 读书笔记
    一些编程试题
    Qt 对话框显示控制按钮
    vc++创建文件目录
    配置ubuntu虚拟机备忘
    Qt QThread 多线程使用
    Qt 程序等待多长时间执行Sleep
    Qt 数字和字符处理总结
    c++ 文件utf-8格式
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5278.html
Copyright © 2011-2022 走看看