题目描述
定义一个正整数是坏的,当且仅当它是 \(42\) 的幂次,否则它是好的。
给定长为 \(n\) 的序列 \(a_i\) ,保证初始所有数都是好的。
接下来 \(q\) 次操作:
1 i
:查询 \(a_i\) 。2 l r x
:将 \(a_l,\cdots,a_r\) 赋值为一个好的数 \(x\) 。3 l r x
:将 \(a_l,\cdots,a_r\) 加上 \(x\) ,重复这一操作直到所有数都变好。
数据范围
- \(1\le n,q\le 10^5\) 。
- \(2\le a_i\le 10^9,1\le x\le 10^9\) 。
时间限制 \(\texttt{5s}\) ,空间限制 \(\texttt{256MB}\) 。
分析
势能线段树经典题目。
值域大约是 \(v=nq=10^{14}\) 级别,坏的数不超过 \(\log_{42}v=8\) 个。
定义势能 \(\varphi\) 为线段树所有节点的坏数个数之和,则 \(\varphi\le 8n\log n\) 。
对线段树每个节点,维护 \(val\) 表示区间内 \(a_i\) 到下一个坏数的最短距离,操作二直接打标记,操作三如果 \(x\lt val\) 也可以打标记,否则暴力递归,以 \(1\) 的代价让 \(\varphi\) 减少 \(1\) 。
时间复杂度 \(\mathcal O(n\log_{42}v+q)\log n\) 。
#include<bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs p<<1|1
using namespace std;
const int maxn=1e5+5;
int n,q;
int a[maxn];
struct node
{
int l,r;
int add,cov,val;
}f[4*maxn];
int get(int x)
{
for(int i=1;;i*=42) if(i>=x) return i-x;
}
void pushcov(int p,int v)
{
f[p].add=0,f[p].cov=v,f[p].val=get(v);
}
void pushadd(int p,int v)
{
if(f[p].cov) return pushcov(p,f[p].cov+v);
assert(v<f[p].val);
f[p].add+=v,f[p].val-=v;
}
void pushdown(int p)
{
if(f[p].cov) pushcov(ls,f[p].cov),pushcov(rs,f[p].cov),f[p].cov=0;
if(f[p].add) pushadd(ls,f[p].add),pushadd(rs,f[p].add),f[p].add=0;
}
void pushup(int p)
{
f[p].val=min(f[ls].val,f[rs].val);
}
void build(int p,int l,int r)
{
f[p].l=l,f[p].r=r;
if(l==r) return f[p].cov=a[l],f[p].val=get(a[l]),void();
int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
pushup(p);
}
void modify(int p,int l,int r,int x)
{
if(l>f[p].r||r<f[p].l) return ;
if(l<=f[p].l&&f[p].r<=r) return pushcov(p,x);
pushdown(p);
modify(ls,l,r,x),modify(rs,l,r,x);
pushup(p);
}
void update(int p,int l,int r,int x)
{
if(l>f[p].r||r<f[p].l) return ;
if(l<=f[p].l&&f[p].r<=r&&(x<f[p].val||f[p].cov)) return pushadd(p,x);
pushdown(p);
update(ls,l,r,x),update(rs,l,r,x);
pushup(p);
}
int query(int p,int pos)
{
if(f[p].l==f[p].r) return f[p].cov;
int mid=(f[p].l+f[p].r)>>1;
pushdown(p);
return query(pos<=mid?ls:rs,pos);
}
signed main()
{
scanf("%lld%lld",&n,&q);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
for(int op=0,l=0,r=0,x=0;q--;)
{
scanf("%lld",&op);
if(op==1) scanf("%lld",&x),printf("%lld\n",query(1,x));
if(op==2) scanf("%lld%lld%lld",&l,&r,&x),modify(1,l,r,x);
if(op==3)
{
scanf("%lld%lld%lld",&l,&r,&x);
do update(1,l,r,x);
while(!f[1].val);
}
}
return 0;
}
标签:10,le,return,log,int,题解,42,Bad
From: https://www.cnblogs.com/peiwenjun/p/18686953