zoukankan      html  css  js  c++  java
  • CF679E Bear and Bad Powers of 42

    XVIII.CF679E Bear and Bad Powers of 42

    一个显然的想法是,观察到可能的值域(\(10^{14}\))内不会有很多(准确地说,一共\(11\)个)\(42\)的整数次幂。于是我们考虑每次暴力修改,则每个数最多被处理\(11\)次,复杂度显然是可以承受的。

    于是我们现在问题就转变为判断一个区间中是否存在\(42\)的整数次幂。

    我们对于每个数,维护这个数到下一个\(42\)的次幂的距离,并在区间上维护这一距离的\(\min\)。在区间加的时候,代表区间加的tag增加,同时代表区间\(\min\)的tag减少。

    假如区间\(\min\)的tag在减少后为\(0\)了,就直接返回找到了;否则,如果其大于\(0\),返回没找到;否则,即其小于\(0\),无法判断有没有找到,需要继续往子区间内遍历。

    假如遍历到一个位置,发现这个位置的区间修改的tag不为\(0\)(这可能意味着这段区间刚刚被进行了一次区间修改,或是访问到了叶节点——叶节点的区间修改tag(即它自己的值)显然是不为\(0\)的),那就可以直接由这个tag推出区间中的\(\min\)(毕竟整个区间的值都是相等的),再返回这个\(\min\)是否为\(0\)即可。

    这也意味着我们的pushdown函数要比较细心:假设当前区间修改tag不为\(0\),显然下传时,应该把儿子的tag全都覆盖掉——区间修改tag赋成下传的tag,区间加的tag赋成\(0\);同时,区间\(\min\)的值也要下传,这就避免了在儿子处再算一遍的局面。

    假设当前区间加tag不为\(0\)(显然,此时区间修改tag肯定为\(0\)),下传时注意判断儿子的区间修改tag是否为\(0\),为\(0\)则加到区间加tag上,否则直接加到区间修改tag上;同时,在修改后,记得同时修改区间\(\min\)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n,m;
    const int lim=11;
    ll pov[20]={1,42,1764,74088,3111696,130691232,5489031744ll,230539333248ll,9682651996416ll,406671383849472ll,17080198121677824ll};
    #define lson x<<1
    #define rson x<<1|1
    #define mid ((l+r)>>1)
    struct SegTree{
    	ll tagmodi,tagadd,mn;
    }seg[400100];
    void ADD(int x,ll y){if(seg[x].tagmodi)seg[x].tagmodi+=y;else seg[x].tagadd+=y;seg[x].mn-=y;}
    void REFRESH(int x){seg[x].mn=*lower_bound(pov,pov+lim,seg[x].tagmodi)-seg[x].tagmodi;}
    void MODI(int x,ll y){seg[x].tagmodi=y,seg[x].tagadd=0,REFRESH(x);}
    void pushdown(int x){
    	if(seg[x].tagmodi){
    		seg[lson].tagmodi=seg[rson].tagmodi=seg[x].tagmodi;
    		seg[lson].mn=seg[rson].mn=seg[x].mn;
    		seg[lson].tagadd=seg[rson].tagadd=0;
    		seg[x].tagmodi=0;
    	}
    	if(seg[x].tagadd)ADD(lson,seg[x].tagadd),ADD(rson,seg[x].tagadd),seg[x].tagadd=0;
    }
    void pushup(int x){seg[x].mn=min(seg[lson].mn,seg[rson].mn);}
    void build(int x,int l,int r){
    	if(l==r){scanf("%lld",&seg[x].tagmodi),REFRESH(x);return;}
    	build(lson,l,mid),build(rson,mid+1,r),pushup(x);
    }
    void setval(int x,int l,int r,int L,int R,int val){
    	if(l>R||r<L)return;
    	if(L<=l&&r<=R){MODI(x,val);return;}
    	pushdown(x),setval(lson,l,mid,L,R,val),setval(rson,mid+1,r,L,R,val),pushup(x);
    }
    bool find(int x,int l,int r){
    	if(seg[x].mn>=0)return seg[x].mn==0;
    	if(seg[x].tagmodi){REFRESH(x);return seg[x].mn==0;}
    	pushdown(x);
    	bool ret=find(lson,l,mid)|find(rson,mid+1,r);
    	pushup(x);
    	return ret;
    }
    bool add(int x,int l,int r,int L,int R,int val){
    	if(l>R||r<L)return false;
    	if(L<=l&&r<=R){
    		ADD(x,val);
    		return find(x,l,r);
    	}
    	pushdown(x);
    	bool ret=add(lson,l,mid,L,R,val)|add(rson,mid+1,r,L,R,val);
    	pushup(x);
    	return ret;
    }
    ll query(int x,int l,int r,int P){
    	if(l==r)return seg[x].tagmodi;
    	pushdown(x);
    	ll ret=(P<=mid?query(lson,l,mid,P):query(rson,mid+1,r,P));
    	pushup(x);
    	return ret;
    }
    //void iterate(int x,int l,int r){if(l==r)printf("(%lld:%lld)",seg[x].tagmodi,seg[x].mn);else pushdown(x),iterate(lson,l,mid),iterate(rson,mid+1,r),pushup(x);}
    int main(){
    	scanf("%d%d",&n,&m);
    	build(1,1,n);
    	for(int i=1,a,b,c,d;i<=m;i++){
    		scanf("%d%d",&a,&b);
    		if(a==1)printf("%lld\n",query(1,1,n,b));
    		else{
    			scanf("%d%d",&c,&d);
    			if(a==2)setval(1,1,n,b,c,d);
    			else while(add(1,1,n,b,c,d));
    		}
    //		iterate(1,1,n),puts("");
    	}
    	return 0;
    } 
    

  • 相关阅读:
    LeetCode:Remove Nth Node From End of List
    链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)
    快速排序partition过程常见的两种写法+快速排序非递归实现
    LeetCode:Permutations, Permutations II(求全排列)
    LeetCode:3Sum, 3Sum Closest, 4Sum
    LeetCode:Two Sum
    判断一个图是否有环
    c++设计一个无法被继承的类
    设计模式--单例模式
    windows多线程同步互斥--总结
  • 原文地址:https://www.cnblogs.com/Troverld/p/14611375.html
Copyright © 2011-2022 走看看