Codeforces 679E - Bear and Bad Powers of 42(线段树+势能分析)
这个 \(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
*/
Codeforces 679E - Bear and Bad Powers of 42(线段树+势能分析)的更多相关文章
- codeforces 679e Bear and Bad Powers of 42
传送门:http://codeforces.com/contest/679/problem/E 题目意思很清晰,给你一个序列,要求你完成以下三个操作: 1.输出A[i] 2.将[a,b]区间的所有数字 ...
- Lucky Array Codeforces - 121E && Bear and Bad Powers of 42 Codeforces - 679E
http://codeforces.com/contest/121/problem/E 话说这题貌似暴力可A啊... 正解是想出来了,结果重构代码,调了不知道多久才A 错误记录: 1.线段树搞混num ...
- DZY Loves Colors CodeForces - 444C (线段树势能分析)
大意:有$n$个格子, 初始$i$位置的颜色为$i$, 美丽值为0, 有两种操作 将区间$[l,r]$内的元素全部改为$x$, 每个元素的美丽值增加$|x-y|$, $y$为未改动时的值 询问区间$[ ...
- CF679E Bear and Bad Powers of 42
一段时间不写线段树标记,有些生疏了 codeforces 679e Bear and Bad Powers of 42 - CHADLZX - 博客园 关键点是:42的次幂,在long long范围内 ...
- [Codeforces 464E] The Classic Problem(可持久化线段树)
[Codeforces 464E] The Classic Problem(可持久化线段树) 题面 给出一个带权无向图,每条边的边权是\(2^{x_i}(x_i<10^5)\),求s到t的最短路 ...
- Codeforces679E. Bear and Bad Powers of 42
传送门 今天子帧的一套模拟题的T3. 考试的时候其实已经想到了正解了,但是一些地方没有想清楚,就没敢写,只打了个暴力. 首先考虑用线段树维护区间信息. 先把每个值拆成两个信息,一是距离他最近的且大于他 ...
- Educational Codeforces Round 6 E. New Year Tree dfs+线段树
题目链接:http://codeforces.com/contest/620/problem/E E. New Year Tree time limit per test 3 seconds memo ...
- Codeforces Round #244 (Div. 2) B. Prison Transfer 线段树rmq
B. Prison Transfer Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/pro ...
- codeforces 893F - Physical Education Lessons 动态开点线段树合并
https://codeforces.com/contest/893/problem/F 题意: 给一个有根树, 多次查询,每次查询对于$x$i点的子树中,距离$x$小于等于$k$的所有点中权值最小的 ...
随机推荐
- 初学python-day6 for循环和流程控制(已更新循环做三角形图形!!)
for循环 1.格式 for 变量 in 集合: 循环体 2.概述 当程序执行for循环,按顺序从集合中获取元素变量保存当前循环得到的值,再去执行循环体.当集合中数据都被取完,则此刻跳 ...
- 4.19——数组双指针——26. 删除有序数组中的重复项 & 27. 删除有序数组中的重复项II & 80. 删除有序数组中的重复项 II
第一次做到数组双指针的题目是80: 因为python的List是可以用以下代码来删除元素的: del List[index] 所以当时的我直接用了暴力删除第三个重复元素的做法,大概代码如下: n = ...
- 【c++ Prime 学习笔记】第4章 表达式
表达式由一个或多个运算对象组成,对表达式求值返回结果. 字面值和变量是最简单的表达式 把运算符和运算对象组合可得到复杂表达式. 4.1 基础 4.1.1 基本概念 一元运算符作用于一个对象,如取地址符 ...
- Vite启动后提示Network: use `--host` to expose
当使用 Vite 构建项目后,发现只有localhost + 端口 服务,没有 IP + 端口服务. 运行npm run dev,终端提示Vite启动后提示Network: use '--host' ...
- 升级 dubbo 小心 default.version
上周遇到个关于升级dubbo 2.6 到2.7的兼容性问题,差点造成线上故障,这里记录下,也给大家提个醒. 问题回放 有一个接口的提供方(dubbo 2.6.6)这么配置接口的版本号 <dubb ...
- LoadRunner12浏览器录制(谷歌火狐)
一.使用谷歌浏览器 下载的版本 65.0.3325.162(正式版本)(64 位)安装之前要记得把电脑现有的谷歌浏览器卸载了. 1.下载地址:https://www.chromedownloads.n ...
- Obsidian中如何记录自己的灵感?
在生活中当中你是否会在某个瞬间产生一个想法,但没过多久就想不起来了,正所谓灵感转瞬即逝,那我们不妨在灵感出现的时候顺手将他记录下来.记录的过程要求简单.方便且不会花费我们太多时间,下面我们介绍一下如何 ...
- 【Docker】Asp.net core在docker容器中的端口问题
还记得[One by one系列]一步步学习docker(三)--实战部署dotnetcore中遇到的问题么?容器内部启动始终是80端口,并不由命令左右. docker run --name cont ...
- Mybatis:插入数据返回自增主键
使用Mybatis作为工具连接MySQL,要求在插入数据之后返回自增主键 一开始也很迷惑,Mybatis使用insert之后,成功返回的是1,失败会报错或返回0,主键去哪找来 后来知道Mybatis可 ...
- [源码解析] PyTorch 分布式(4)------分布式应用基础概念
[源码解析] PyTorch 分布式(4)------分布式应用基础概念 目录 [源码解析] PyTorch 分布式(4)------分布式应用基础概念 0x00 摘要 0x01 基本概念 0x02 ...