【学习笔记】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);
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值