Codeforces 679E - Bear and Bad Powers of 42(线段树+势能分析)

Codeforces 题目传送门 & 洛谷题目传送门

这个 \(42\) 的条件非常奇怪,不过注意到本题 \(a_i\) 范围的最大值为 \(10^{14}\),而在值域范围内 \(42\) 的幂的个数最多只有 \(13\) 个,故考虑用类似于 seg-beats 的方法解决这道题。

首先不考虑操作 \(2\)(区间赋值操作),我们很容易发现一个性质,那就是我们对一个区间进行区间加的操作,每额外进行一次,都是因为存在某个数 \(a_i\) 达到了 \(42\) 的整数次幂,而我们的 \(a_i\) 是单调递增的,故每个数最多只可能出现 \(13\) 次成为 \(42\) 的整数次幂的时刻,故总操作次数最多只有 \(1.3\times 10^6\),于是暴力加是不会出问题的。故现在问题转化为怎样求一个区间中是否存在 \(42\) 的整数次幂。

考虑记 \(b_i\)\(\geq a_i\) 的最小的 \(42\) 的整数次幂。显然我们对区间进行 \(+v\) 操作相当于将对应区间 \(b_i-a_i\) 的值 \(-v\),这个操作可以用线段树维护。当然,我们进行一次 \(-v\) 操作后会导致某些 \(b_i-a_i\) 变成负数,也就是说,此时的 \(b_i\) 不再是 \(\geq a_i\) 的最小的 \(42\) 的整数次幂了,我们对于这样的 \(i\) 暴力修改 \(b_i\) 的值,具体来说,线段树维护 \(b_i-a_i\) 的最小值,每次修改后在线段树上进行一遍递归,当递归到某个区间时若该区间 \(b_i-a_i\) 的最小值 \(\geq 0\) 则意味着不存在 \(b_i-a_i<0\)\(i\),直接 return 就行了,否则继续递归左右儿子,递归到叶子节点直接把值改掉。由之前的分析可知最多修改次数也是 \(1.3\times 10^6\),如此暴力进行下去直到全局 \(b_i-a_i\) 不为 \(0\)(不存在 \(a_i=b_i\))即可,复杂度 \(q\log_{42}(qa_i)\log n\)

接下来考虑加上区间赋值操作之后怎么处理。由于我们有区间赋值操作,故刚才总操作次数 \(1.3\times 10^6\) 的复杂度上界就不再存在了(不过听说按照之前的套路暴力赋值也能过?大概是因为这题数据比较难卡罢)。不过作为精益求精的 OIer,我们要思考更优秀的做法。不难发现进行一遍区间赋值之后会使很多位置上的值变成同一个值,也就是说我们区间赋值操作会将序列划分成一段段,我们考虑用 multiset 维护每一段的右端点,这样查询的时候只用查询对应位置所在段的右端点的值即可。

具体来说,初始状态下所有元素都单独成段,也就是每个元素都是对应段的右端点。当我们进行 \(2\) 操作的时候,相当于 \([l,r]\) 成为了完整的一段,故我们将 multiset\([l,r-1]\) 内的元素全部删除并插入 \(r\),由于我们只关心段的右端点的值即可,于是我们将线段树 \([l,r-1]\) 位置上赋上 INF(为了保证它们永远不会变成负数),暂且忽略它们的存在,并将 \(r\) 位置上的值改为待赋的值。当然,这样也会导致 \(l-1\) 成为新的段的右端点,故在 multiset 中插入 \(l-1\),并将 \(l-1\) 位置上的值改为真实值(原本 \(l-1\) 所在段的右端点的值)即可。其余都和不考虑操作 \(2\) 的版本一样。

复杂度还是 \(q\log_{42}(qa_i)\log n\)

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
	#define FILE_SIZE 1<<23
	char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
	inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
	inline void putc(char x){(*p3++=x);}
	template<typename T> void read(T &x){
		x=0;char c=getchar();T neg=0;
		while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
		while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
		if(neg) x=(~x)+1;
	}
	template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
	template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
	void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=1e5;
const int LOG_42=13;
const ll INF=1e18;
int n,qu;set<int> st;
ll pw42[LOG_42+2];
ll get42(ll v){return *lower_bound(pw42,pw42+LOG_42+1,v);}
struct node{int l,r;ll v,tag_lz,add_lz;} s[MAXN*4+5];
ll a[MAXN+5],nxt42[MAXN+5];
void pushup(int k){s[k].v=min(s[k<<1].v,s[k<<1|1].v);}
void pushdown(int k){
	if(s[k].tag_lz!=0){
		s[k<<1].v=s[k].tag_lz;s[k<<1|1].v=s[k].tag_lz;
		s[k<<1].tag_lz=s[k].tag_lz;s[k<<1|1].tag_lz=s[k].tag_lz;
		s[k].tag_lz=0;
	}
	if(s[k].add_lz!=0){
		s[k<<1].v+=s[k].add_lz;s[k<<1|1].v+=s[k].add_lz;
		s[k<<1].add_lz+=s[k].add_lz;s[k<<1|1].add_lz+=s[k].add_lz;
		s[k].add_lz=0;
	}
}
void build(int k,int l,int r){
	s[k].l=l;s[k].r=r;
	if(l==r){nxt42[l]=get42(a[l]);s[k].v=nxt42[l]-a[l];return;}
	int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
	pushup(k);
}
void assign(int k,int l,int r,ll x){
	if(l<=s[k].l&&s[k].r<=r){s[k].tag_lz=s[k].v=x;return;}
	pushdown(k);int mid=s[k].l+s[k].r>>1;
	if(r<=mid) assign(k<<1,l,r,x);
	else if(l>mid) assign(k<<1|1,l,r,x);
	else assign(k<<1,l,r,x),assign(k<<1|1,mid+1,r,x);
	pushup(k);
}
void change_v(int k,int p,ll x){
	if(s[k].l==s[k].r){
		nxt42[s[k].l]=get42(x);s[k].v=nxt42[s[k].l]-x;return;
	} pushdown(k);int mid=s[k].l+s[k].r>>1;
	if(p<=mid) change_v(k<<1,p,x);
	else change_v(k<<1|1,p,x);
	pushup(k);
}
void add(int k,int l,int r,ll x){
	if(l<=s[k].l&&s[k].r<=r){s[k].add_lz+=x;s[k].v+=x;return;}
	pushdown(k);int mid=s[k].l+s[k].r>>1;
	if(r<=mid) add(k<<1,l,r,x);
	else if(l>mid) add(k<<1|1,l,r,x);
	else add(k<<1,l,r,x),add(k<<1|1,mid+1,r,x);
	pushup(k);
}
void killneg(int k){
	if(s[k].v>=0) return;
	if(s[k].l==s[k].r){
		s[k].v=nxt42[s[k].l]-s[k].v;
		nxt42[s[k].l]=get42(s[k].v);
		s[k].v=nxt42[s[k].l]-s[k].v;
		return;
	} pushdown(k);killneg(k<<1);killneg(k<<1|1);
	pushup(k);
}
ll getdif(int k,int p){
	if(s[k].l==s[k].r) return s[k].v;
	int mid=s[k].l+s[k].r>>1;pushdown(k);
	if(p<=mid) return getdif(k<<1,p);
	else return getdif(k<<1|1,p);
}
ll query(int k,int p){
	if(s[k].l==s[k].r) return nxt42[s[k].l]-s[k].v;
	int mid=s[k].l+s[k].r>>1;pushdown(k);
	if(p<=mid) return query(k<<1,p);
	else return query(k<<1|1,p);
}
void split(int x){
	int nxt=*st.lower_bound(x);
	if(nxt==x) return;st.insert(nxt);
	change_v(1,x,query(1,nxt));st.insert(x);
}
int main(){
	pw42[0]=1;for(int i=1;i<=LOG_42;i++) pw42[i]=pw42[i-1]*42ll;
	scanf("%d%d",&n,&qu);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]),st.insert(i);
	build(1,1,n);
	while(qu--){
		int opt;scanf("%d",&opt);
		if(opt==1){int x;scanf("%d",&x);printf("%lld\n",query(1,*st.lower_bound(x)));}
		else if(opt==2){
			int l,r,v;scanf("%d%d%d",&l,&r,&v);
			if(l>1) split(l-1);split(r);
			st.erase(st.lower_bound(l),st.lower_bound(r));
			if(l<r) assign(1,l,r-1,INF);
			change_v(1,r,v);
		} else {
			int l,r,v;scanf("%d%d%d",&l,&r,&v);
			if(l>1) split(l-1);split(r);
			do {
				add(1,l,r,-v);killneg(1);
			} while(s[1].v==0);
		}
	}
	return 0;
}
/*
6 13
40 1700 7 1672 4 1722
3 2 4 42
1 2
1 3
1 4
3 2 6 50
1 2
1 4
1 6
2 3 4 41
3 1 5 1
1 1
1 3
1 5
*/
posted @ 2021-02-28 20:52  tzc_wk  阅读(84)  评论(0)    收藏  举报