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;
} 

posted @ 2021-04-02 16:38  Troverld  阅读(80)  评论(0编辑  收藏  举报