卧薪尝胆,厚积薄发。
Bear and Bad Powers of 42
Date: Mon Feb 25 15:03:11 CST 2019 In Category: NoCategory

Description:

维护一个序列,支持单点查询、区间修改、区间加,如果某次区间加操作完后,序列中有一个元素是 $42$ 的幂,那么就需要一直做这个操作直到序列中不存在 $42$ 的幂。
$1\leqslant n,q\leqslant 10^5$

Solution:

先考虑如果没有区间赋值怎么做,可以用线段树维护,对每个位置维护一个 $lev$ 表示大于等于它的第一个 $42$ 的幂是几,然后再维护一个 $mind$ 表示这个位置的值与大于等于它的第一个 $42$ 的幂的差,每次区间加不更新 $lev$ ,之后 $update$ 一下,把 $mind$ 小于 $0$ 的位置暴力更新 $lev$ ,因为 $long\ long$ 范围内 $42$ 的倍数很少,因此复杂度是对的,在考虑有区间赋值怎么做,可以对每个区间维护一个 $same$ 表示整个区间是否都相同,在 $update$ 的时候如果 $same=true$ ,就计算一下最终的值,然后打一个区间赋值标记退出,复杂度是对的。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int n,q;
#define MAXN 100010
typedef long long ll;
ll a[MAXN];
ll power[12];
struct node
{
int lc,rc;
ll lev,add,set,mind;
bool same;
}t[MAXN << 1];
int ptr = 0;
int newnode(){return ++ptr;}
int root;
#define mid ((l + r) >> 1)
int getlev(ll val){return lower_bound(power,power + 12,val) - power;}
void pushup(int rt)
{
int lc = t[rt].lc,rc = t[rt].rc;
t[rt].mind = min(t[lc].mind,t[rc].mind);
if(t[lc].same && t[rc].same && t[lc].lev == t[rc].lev && t[lc].mind == t[rc].mind)
{
t[rt].same = true;t[rt].lev = t[lc].lev;
}
else t[rt].same = false;
return;
}
void addtag(int rt,ll val)
{
if(t[rt].set != -1)t[rt].set += val;
else t[rt].add += val;
t[rt].mind -= val;
return;
}
void settag(int rt,ll val)
{
if(t[rt].add != 0)t[rt].add = 0;
t[rt].set = val;
t[rt].same = true;
t[rt].lev = getlev(val);
t[rt].mind = power[t[rt].lev] - val;
return;
}
void pushdown(int rt)
{
if(t[rt].add != 0)
{
addtag(t[rt].lc,t[rt].add);addtag(t[rt].rc,t[rt].add);
t[rt].add = 0;
return;
}
if(t[rt].set != -1)
{
settag(t[rt].lc,t[rt].set);settag(t[rt].rc,t[rt].set);
t[rt].set = -1;
return;
}
}
void build(int &rt,int l,int r)
{
rt = newnode();
t[rt].set = -1;
if(l == r)
{
t[rt].same = true;
t[rt].lev = getlev(a[l]);
t[rt].mind = power[t[rt].lev] - a[l];
return;
}
build(t[rt].lc,l,mid);
build(t[rt].rc,mid + 1,r);
pushup(rt);
return;
}
void update(int rt,int l,int r)
{
if(t[rt].same)
{
while(t[rt].mind < 0)
{
++t[rt].lev;
t[rt].mind = power[t[rt].lev] - (power[t[rt].lev - 1] - t[rt].mind);
}
settag(rt,power[t[rt].lev] - t[rt].mind);
return;
}
pushdown(rt);
if(t[t[rt].lc].mind < 0)update(t[rt].lc,l,mid);
if(t[t[rt].rc].mind < 0)update(t[rt].rc,mid + 1,r);
pushup(rt);
return;
}
void set(int rt,int L,int R,ll val,int l,int r)
{
if(L <= l && r <= R){settag(rt,val);return;}
pushdown(rt);
if(L <= mid)set(t[rt].lc,L,R,val,l,mid);
if(R > mid)set(t[rt].rc,L,R,val,mid + 1,r);
pushup(rt);
return;
}
void add(int rt,int L,int R,ll val,int l,int r)
{
if(L <= l && r <= R){addtag(rt,val);return;}
pushdown(rt);
if(L <= mid)add(t[rt].lc,L,R,val,l,mid);
if(R > mid)add(t[rt].rc,L,R,val,mid + 1,r);
pushup(rt);
return;
}
ll query(int rt,int p,int l,int r)
{
if(l == r)return power[t[rt].lev] - t[rt].mind;
pushdown(rt);
if(p <= mid)return query(t[rt].lc,p,l,mid);
else return query(t[rt].rc,p,mid + 1,r);
}
int main()
{
power[0] = 1;
for(int i = 1;i <= 11;++i)power[i] = power[i - 1] * 42;
scanf("%d%d",&n,&q);
for(int i = 1;i <= n;++i)cin >> a[i];
build(root,1,n);
int opt,l,r;
ll x;
for(int i = 1;i <= q;++i)
{
scanf("%d",&opt);
if(opt == 1)
{
cin >> x;
cout << query(root,x,1,n) << endl;
}
else
{
scanf("%d%d",&l,&r);
cin >> x;
if(opt == 3)
{
add(root,l,r,x,1,n);
update(root,1,n);
while(t[root].mind == 0)
{
add(root,l,r,x,1,n);
update(root,1,n);
}
}
else set(root,l,r,x,1,n);
}
}
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡