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$的所有点中权值最小的 ...
随机推荐
- 一站式交付体验:云效+Kubernetes
背景 云效依托于阿里巴巴研发效能多年规模化持续交付,赋能云上开发者专为云端用户提供的一站式研发协作平台.Kubernetes,由Google开源的容器集群管理平台,面向运维侧提供自动化的集群和应用管理 ...
- 分割迭代器Spliterator源码文档翻译
前言 身体是革命的本钱,不舒服了2周,现在好点了. 学习JDK8的Stream,Spliterator这个分割迭代器是必须要重视的. Notes:下方蓝色文字是自己的翻译(如果有问题请指正).黑色文字 ...
- seata整合多数据源
seata整合多数据源 一.背景 二.整合步骤 1.seata server的搭建 2.引入数据源切换组件 3.引入seata组件 4.配置多数据源 5.关闭seata自己默认的数据源代理 6.配置s ...
- 常用JAVA API :HashSet 和 TreeSet
set容器的特点是不包含重复元素,也就是说自动去重. HashSet HashSet基于哈希表实现,无序. add(E e)//如果容器中不包含此元素,则添加. clear()//清空 contain ...
- 最短路计数(SPFA× Dijkstra√)
题目描述 给出一个n个顶点m条边的无向无权图,顶点编号为1−n.问从顶点1开始,到其他每个点的最短路有几条. 输入格式 第一行包含2个正整数n,m,为图的顶点数与边数. 接下来M行,每行2个正整数x, ...
- 第06课 OpenGL 纹理映射
纹理映射: 在这一课里,我将教会你如何把纹理映射到立方体的六个面. 学习 texture map 纹理映射(贴图)有很多好处.比方说您想让一颗导弹飞过屏幕.根据前几课的知识,我们最可行的办法可能是很多 ...
- Docker 添加--insecure-registry 私有镜像仓库
方法一 [root@k8s-master01]# vi /usr/lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd --inse ...
- C++ IO基础
一:c++I/O处理,按照数据输入输出的过程,形象的将其看做流.数据在流中进行传播. 所有的流有两个基类:ios和streambuf类 streambuf:提供对缓冲区的基本操作,设置缓冲区等 ios ...
- 什么是 Webhook?
1. 什么是 Webhook? Webhook 是一个 API 概念,是微服务 API 的使用范式之一,也被成为反向 API,即前端不主动发送请求,完全由后端推送:举个常用例子,比如你的好友发了一条朋 ...
- python基本数据类型操作
str 字符串 #1.进行字符串转换 首字母转换成大写 # name = 'wangjianhui' # v = name.capitalize() # print(v) #2. 字符转换小写 # n ...