CF679E Bear and Bad Powers of 42 题解
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;
}