zoukankan      html  css  js  c++  java
  • 【CF679E】Bear and Bad Powers of 42(ODT+线段树)

    点此看题面

    • 定义(42)的幂是坏的数,其余的数是好的数,初始给定一个长度为(n)的好数序列。
    • 要求支持三种操作:单点询问;区间赋值;区间加法,重复这一过程直至所有数都是好的。
    • (n,qle10^5,a_i,xle10^9)

    线段树+势能分析

    暂且不考虑区间赋值操作。

    因为(42)的幂的数量很少,我们只要暴力修改,复杂度是(O(nlognlogV))的。

    具体地,对于每个位置我们记下大于等于它的第一个(42)的幂与它的差值,修改时如果差值大于修改值直接打标记,否则暴力单点修改。

    若一次修改之后最小差值为(0),说明存在坏的数,继续修改即可。

    (ODT)处理区间赋值

    然而这道题当中有区间赋值,如果每次直接区间赋值,可能导致很多数获得高势能。

    因此我们必须要把每个相同的值域段信息统一维护在左端点上,而每次要询问某个点或修改某个区间的时候需要保证操作的是若干完整段,又要实现值域段的拆分。

    这种区间赋值问题很容易想到(ODT)

    而在线段树上,对于每个值域段非左端点的部分,我们给它们打上抹杀标记,并在操作时忽略它们的影响。即若修改到这部分直接退出,若询问到这部分与下一个(42)的幂的最小差值直接返回(INF)

    代码:(O(nlognlogV))

    #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 100000
    #define LL long long
    using namespace std;
    int n;LL a[N+5];I LL Nxt(Con LL& x) {LL t=1;W(t<x) t*=42;return t;}
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	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...);}
    	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('
    ');}
    }using namespace FastIO;
    class SegmentTree
    {
    	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]=min(D[x<<1]?1e18:V[x<<1],D[x<<1|1]?1e18:V[x<<1|1]))
    		#define PD(x) (D[x]&&(D[x<<1]=D[x<<1|1]=1,D[x]=F[x]=0),F[x]&&(T(x<<1,F[x]),T(x<<1|1,F[x]),F[x]=0))
    		#define T(x,v) (!D[x]&&(V[x]-=v,F[x]+=v))
    		int D[N<<2];LL V[N<<2],F[N<<2];
    	public:
    		I void Bd(PT)//建树
    		{
    			if(l==r) return (void)(V[rt]=Nxt(a[l])-a[l]);RI mid=l+r>>1;Bd(LT),Bd(RT),PU(rt);
    		}
    		I void U(CI x,Con LL& v,PT)//单点赋值
    		{
    			if(l==r) return (void)(a[l]=v,V[rt]=Nxt(a[l])-a[l],D[rt]=0);
    			RI mid=l+r>>1;PD(rt),x<=mid?U(x,v,LT):U(x,v,RT),PU(rt);
    		}
    		I void E(CI L,CI R,PT)//区间抹杀
    		{
    			if(D[rt]) return;if(L<=l&&r<=R) return (void)(D[rt]=1);RI mid=l+r>>1;
    			PD(rt),L<=mid&&(E(L,R,LT),0),R>mid&&(E(L,R,RT),0),PU(rt);
    		}
    		I void M(CI L,CI R,CI v,PT)//区间减法
    		{
    			if(D[rt]) return;if(l==r) return (void)(a[l]=Nxt(a[l])-V[rt]+v,V[rt]=Nxt(a[l])-a[l]);//单点直接修改
    			if(L<=l&&r<=R&&V[rt]>v) return (void)T(rt,v);RI mid=l+r>>1;//最小差值大于v才能直接区间打标记
    			PD(rt),L<=mid&&(M(L,R,v,LT),0),R>mid&&(M(L,R,v,RT),0),PU(rt);
    		}
    		I LL Q(CI x,PT)//单点询问
    		{
    			if(l==r) return Nxt(a[l])-V[rt];RI mid=l+r>>1;return PD(rt),x<=mid?Q(x,LT):Q(x,RT);
    		}
    		I LL Mn(CI L,CI R,PT)//区间询问最小差值
    		{
    			if(D[rt]) return 1e18;if(L<=l&&r<=R) return V[rt];RI mid=l+r>>1;
    			return PD(rt),min(L<=mid?Mn(L,R,LT):1e18,R>mid?Mn(L,R,RT):1e18);
    		}
    }S;
    namespace ODT//ODT维护区间赋值
    {
    	#define IT set<Il>::iterator
    	struct Il {int l,r;I Il(CI a=0,CI b=0):l(a),r(b){}I bool operator < (Con Il& o) Con {return l<o.l;}};set<Il> s;
    	I IT Split(CI x)//拆出一个以x为左端点的区间
    	{
    		IT it=s.lower_bound(x);if(it->l==x) return it;RI l=(--it)->l,r=it->r;LL v=S.Q(l);
    		return S.U(x,v),s.erase(it),s.insert(Il(l,x-1)),s.insert(Il(x,r)).first;
    	}
    	I void Assign(CI l,CI r,CI v)//区间赋值
    	{
    		IT tr=Split(r+1),tl=Split(l);S.U(l,v),l^r&&(S.E(l+1,r),0),s.erase(tl,tr),s.insert(Il(l,r));
    	}
    }
    int main()
    {
    	RI Qt,i;for(read(n,Qt),i=1;i<=n;++i) read(a[i]),ODT::s.insert(ODT::Il(i,i));S.Bd();
    	RI op,x,y,z;W(Qt--) switch(read(op,x),op)
    	{
    		case 1:ODT::Split(x),writeln(S.Q(x));break;case 2:read(y,z),ODT::Assign(x,y,z);break;
    		case 3:read(y,z),ODT::Split(y+1),ODT::Split(x),S.M(x,y,z);W(!S.Mn(x,y)) S.M(x,y,z);break;//最小差值为0说明存在坏的数
    	}return clear(),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    将ip地址转成二进制数据,除基本输入输出不调用库函数实现
    将ip地址转成二进制数据
    一种合并链表方法实现 严蔚敏 数据结构
    阿里巴巴集团2014年校园招聘系统工程师北京笔试题
    显示模态模态对话框和非模态对话框
    MFC中利用CString和Format成员函数将数字格式化输出
    ObjectARX2012错误1 fatal error C1083: 无法打开包括文件:“arxHeaders.h”: No such file or directory; fatal error C1083: 无法打开包括文件:“map”: No such file or directory
    Metasploit 读书笔记-神器Meterpreter
    解决:kali linux 在vmware 虚拟机中使用bridge模式上网的问题
    metasploit 读书笔记-EXPLOITATION
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF679E.html
Copyright © 2011-2022 走看看