【学习笔记】CF679E Bear and Bad Powers of 42

我是小丑,这道题读错了整整两次!!

还是用线段树维护。发现一个神奇的事情,这题只要能快速判断区间内是否存在 42 42 42的次幂,然后用 Segment Tree Beats \text{Segment\ Tree\ Beats} Segment Tree Beats维护就完了。这可以通过维护与最小的 42 42 42次幂的差值来实现,因为这样区间加时可以快速维护。

可以感性认为复杂度是对的。 根据 Segment Tree Beats \text{Segment\ Tree\ Beats} Segment Tree Beats的思想我们要设计势能函数来分析复杂度,但是这题的势能比较奇怪 所以就咕了。

复杂度据说是 O ( n log ⁡ n log ⁡ 42 V ) O(n\log n\log_{42} V) O(nlognlog42V)

写了一发,发现难点在于各种标记的处理比较复杂,可能这也是本题复杂度比较难分析的原因。所以这题难度还是低估了。

#include<bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define inf 0x3f3f3f3f using namespace std; const int N=1e5+5; int n,m,a[N]; ll nums[15]; struct node{ ll min,val,tagnums; //fixed int tag; }t[N<<2]; void pushup(int p){ t[p].min=min(t[p<<1].min,t[p<<1|1].min); } ll calc(ll x){ int ps=lower_bound(nums,nums+10,x)-nums; assert(ps<=9);return nums[ps]-x; } void build(int p,int l,int r){ if(l==r){ t[p].tag=1,t[p].val=a[l],t[p].min=calc(a[l]); return; } int mid=l+r>>1; build(p<<1,l,mid),build(p<<1|1,mid+1,r); pushup(p); } void cover(int p,ll val){ t[p].tag=1,t[p].val=val,t[p].tagnums=0,t[p].min=calc(val); } void add(int p,ll val){ //fixed t[p].tagnums+=val,t[p].min-=val; assert(t[p].min>=0); } void pushdown(int p){ //先下传区间覆盖标记,再下传区间加标记 if(t[p].tag){ cover(p<<1,t[p].val),cover(p<<1|1,t[p].val); t[p].tag=0; } if(t[p].tagnums){ add(p<<1,t[p].tagnums),add(p<<1|1,t[p].tagnums); t[p].tagnums=0; } } void modify(int p,int l,int r,int ql,int qr,int val){ if(ql<=l&&r<=qr){ cover(p,val); return; } int mid=l+r>>1;pushdown(p); if(ql<=mid)modify(p<<1,l,mid,ql,qr,val); if(mid<qr)modify(p<<1|1,mid+1,r,ql,qr,val); pushup(p); } void addnums(int p,int l,int r,int ql,int qr,ll val){ //可以直接返回 if(ql<=l&&r<=qr&&t[p].min>=val){ add(p,val); return; } if(ql<=l&&r<=qr&&t[p].tag){ cover(p,t[p].val+t[p].tagnums+val); return; } //叶子节点 if(l==r){ t[p].val+=val,t[p].min=calc(t[p].val+t[p].tagnums); return; } int mid=l+r>>1;pushdown(p); if(ql<=mid)addnums(p<<1,l,mid,ql,qr,val); if(mid<qr)addnums(p<<1|1,mid+1,r,ql,qr,val); pushup(p); } ll query(int p,int l,int r,int x){ if(l==r){ assert(t[p].tag); return t[p].val+t[p].tagnums; } int mid=l+r>>1;pushdown(p); return x<=mid?query(p<<1,l,mid,x):query(p<<1|1,mid+1,r,x); } ll querymin(int p,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr){ assert(t[p].min>=0); return t[p].min; } int mid=l+r>>1; if(qr<=mid)return querymin(p<<1,l,mid,ql,qr); if(mid<ql)return querymin(p<<1|1,mid+1,r,ql,qr); return min(querymin(p<<1,l,mid,ql,qr),querymin(p<<1|1,mid+1,r,ql,qr)); } signed main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>m;nums[0]=1; for(int i=1;i<=9;i++){ nums[i]=nums[i-1]*42; assert(nums[i]>=0); assert(nums[i]<=1e18); } for(int i=1;i<=n;i++)cin>>a[i]; build(1,1,n); for(int i=1;i<=m;i++){ int type,l,r,x; cin>>type; if(type==1){ cin>>x;cout<<query(1,1,n,x)<<"\n"; } else if(type==2){ cin>>l>>r>>x; modify(1,1,n,l,r,x); } else{ cin>>l>>r>>x; addnums(1,1,n,l,r,x); while(querymin(1,1,n,l,r)==0){ addnums(1,1,n,l,r,x); } } } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17529943.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(9)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
历史上的今天:
2022-07-04 【学习笔记】图的连通性与回路
2022-07-04 【简要题解】OI Online能力测试校内赛(Round One)T2~T4
2022-07-04 【学习笔记】阶段测试1
点击右上角即可分享
微信分享提示