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$的所有点中权值最小的 ...
随机推荐
- 5个步骤,教你瞬间明白线程和线程安全.md
记得刚来杭州面试的时候,有一家公司的技术总监问了我这样一个问题:你来说说有哪些线程安全的类?我心里一想,这我早都背好了,稀里哗啦说了一大堆. 他又接着问:那你再来说说什么是线程安全?--然后我就GG了 ...
- LeetCode:“剑指 Offer”
LeetCode:"剑指 Offer" 刷题小菜鸡,花了几天时间做了一遍 LeetCode 上给出的 "剑指 Offer" 在此做一下记录 LeetCode主页 ...
- [对对子队]事后总结Beta
设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 要做一个游戏,定义的很清楚,实现出来的效果贴近定义,对用户和场景有清晰描述 我们达到目标了么(原计划的功 ...
- [no_code][Alpha]项目展示博客
$( "#cnblogs_post_body" ).catalog() 团队项目链接 github 后端 github OCR文档-含部分所需测试代码目前private API调用 ...
- [no_code]OCR表格处理——功能规格说明书
项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 功能规格说明书 我们在这个课程的目标是 远程协同工作,采用最新技术开发软件 这个作业在哪个具体方面 ...
- CodeForces-1076E Vasya and a Tree
CodeForces - 1076E Problem Description: Vasya has a tree consisting of n vertices with root in verte ...
- repo学习总结
转载:https://blog.csdn.net/salmon_zhang/article/details/79180075 1. repo简介 repo是Google开发的用于管理Android版本 ...
- Ubuntu鼠标变十字 不能点击
出现这种情况,应该是bash 直接运行了python文件 系统中出现了一个import 进程. python文件中除了注释应该是import在最前边 ps -ef|grep import 可以查看系统 ...
- 把二叉树打印成多行 牛客网 剑指Offer
把二叉树打印成多行 牛客网 剑指Offer 题目描述 从上到下按层打印二叉树,同一层结点从左至右输出.每一层输出一行 # class TreeNode: # def __init__(self, x) ...
- Markdown使用方式
区块 区块引用在段落开头使用>,后面紧跟一个空格符号 > 区块引用 > XXX > XXX 高级技巧 HTML元素 居中 <center>XXX</cent ...