Live2D

CF679E Bear and Bad Powers of 42 题解

link

Solution

考虑一种做法,因为合法答案值域里 \(42\) 幂次的个数很少,所以我们可以对于每一个位置记录它到下一个 \(42\) 次幂的差值,然后用线段树维护,然后每次赋值直接赋值即可,修改的话如果最小值 \(>v\) 直接打懒标记即可,否则就继续递归,如果一个区间值全都相同(真实值而非差值),也直接修改。

考虑证明复杂度。考虑假如我们能够对于一个相同颜色段快速维护,那么考虑势能分析,一个状态总势能就是每一段相同的颜色段后面的 \(42\) 幂次个数。那么 \(2\) 操作最多会增加 \(\log_{42} V\) 的势能,对于 \(3\) 操作而言,它最多只会增加一个区间,然后还会消耗势能,所以总状态总势能最多是 \(q\log_{42} V\)。然后如果用线段树维护的话就是 \(q\log_{42} V\log n\) 的。

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define int long long
#define MAXN 100005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

int n,q,a[MAXN],Z[15];

int getit (int v){return lower_bound (Z + 1,Z + 10,v) - Z;}

void init (){
	Z[0] = 1;
	for (Int i = 1;i <= 9;++ i) Z[i] = Z[i - 1] * 42;
}

struct Segment{
	int tag1[MAXN << 2],tag2[MAXN << 2],tag3[MAXN << 2],minv[MAXN << 2];
	void pushadd1 (int x,int val,int pos){
		tag1[x] = minv[x] = val,tag2[x] = pos,tag3[x] = 0;
	}
	void pushadd2 (int x,int v){
		if (tag2[x]){
			tag1[x] -= v;
			while (tag1[x] < 0) tag1[x] += Z[tag2[x] + 1] - Z[tag2[x]],tag2[x] ++;
//			cout << "bitch ??  " << x << ": " << tag1[x] << endl;
			minv[x] = tag1[x];
		}
		else minv[x] -= v,tag3[x] += v;
	}
	void pushdown (int x){
		if (tag2[x]) pushadd1 (x << 1,tag1[x],tag2[x]),pushadd1 (x << 1 | 1,tag1[x],tag2[x]),tag1[x] = tag2[x] = 0;
		if (tag3[x]) pushadd2 (x << 1,tag3[x]),pushadd2 (x << 1 | 1,tag3[x]),tag3[x] = 0;
	}
	void pushup (int x){
		minv[x] = min (minv[x << 1],minv[x << 1 | 1]);
//		if (tag1[x << 1] == tag1[x << 1 | 1]) tag2[x] = tag2[x << 1],tag1[x] = tag1[x << 1];
//		else tag1[x] = tag2[x] = 0;
	}
	void modify (int x,int l,int r,int ql,int qr,int v,int pos){
		if (l >= ql && r <= qr) return pushadd1 (x,v,pos);
		int mid = l + r >> 1;pushdown (x);
		if (ql <= mid) modify (x << 1,l,mid,ql,qr,v,pos);
		if (qr > mid) modify (x << 1 | 1,mid + 1,r,ql,qr,v,pos);
		pushup (x);
	}
	void change (int x,int l,int r,int ql,int qr,int v){
		if (l >= ql && r <= qr && (minv[x] >= v || tag2[x])) return pushadd2 (x,v);
		int mid = l + r >> 1;pushdown (x);
		if (ql <= mid) change (x << 1,l,mid,ql,qr,v);
		if (qr > mid) change (x << 1 | 1,mid + 1,r,ql,qr,v);
		pushup (x);
	}
	int query (int x,int l,int r,int pos){
		if (l == r) return Z[tag2[x]] - tag1[x];
		int mid = l + r >> 1;pushdown (x);
		if (pos <= mid) return query (x << 1,l,mid,pos);
		else return query (x << 1 | 1,mid + 1,r,pos);
	}
}tree;

signed main(){
	init (),read (n,q);
	for (Int i = 1;i <= n;++ i) read (a[i]),tree.modify (1,1,n,i,i,Z[getit (a[i])] - a[i],getit (a[i]));
	while (q --> 0){
		int typ,l,r,x;read (typ);
		if (typ == 1) read (x),write (tree.query (1,1,n,x)),putchar ('\n');
		else if (typ == 2) read (l,r,x),tree.modify (1,1,n,l,r,Z[getit (x)] - x,getit (x));
		else{
			read (l,r,x);
			do{
				tree.change (1,1,n,l,r,x); 
			}while (!tree.minv[1]);
		}  
	}
	return 0;
}
posted @ 2022-02-25 20:57  Dark_Romance  阅读(31)  评论(0编辑  收藏  举报