线段树优化DP求调

P1725 琪露诺

MvemiY @ 2023-08-10 21:49:52

#include<bits/stdc++.h>
#define lc(x) x << 1
#define rc(x) x << 1 | 1
using namespace std;
const int MAXN = 2e5 + 5;
int n, L, R, a[MAXN], f[MAXN], ans = INT_MIN, SGT[4*MAXN], id[MAXN];
inline bool in(int tL, int tR, int l, int r){
    return l <= tL && tR <= r;
}
inline bool out(int tL, int tR, int l, int r){
    return l > tR || r < tL;
}
inline void pushup(int u){
    SGT[u] = max(SGT[lc(u)], SGT[rc(u)]);
}
void build(int u, int tL, int tR){
    if(tL == tR){
        SGT[u] = f[tL];
        id[tL] = u;
        return ;
    }
    int mid = (tL+tR) >> 1;
    build(lc(u), tL, mid);
    build(rc(u), mid+1, tR);
    pushup(u); 
}
void update(int x, int k){
    int u = id[x];
    SGT[u] = k;
    u >>= 1;
    while(u){
        pushup(u);
        u >>= 1;
    }
}
int query(int u, int tL, int tR, int l, int r){
    if(in(tL, tR, l, r))
        return SGT[u];
    if(out(tL, tR, l, r))
        return -0x3f3f3f3f;
    int mid = (tL+tR) >> 1;
    return max(query(lc(u), tL, mid, l, r), query(rc(u), mid+1, tR, l, r));
}
int main(){
    memset(f, -0x3f, sizeof(f));
    cin >> n >> L >> R;
    for(int i = 0; i <= n; i++)
        cin >> a[i];
    f[0] = 0;
    build(1, 0, n);
    for(int i = L; i <= n; i++){
        int k = query(1, 1, n, max(0, i-R), i-L);
        if(f[i] < k + a[i]){
            f[i] = k + a[i];
            update(i, k+a[i]);
        }
    }
    for(int i = n - R + 1; i <= n; i++)
        ans = max(ans, f[i]);
    cout << ans;
    return 0;
} 

用单调队列打完觉得可以用线段树做,但是爆灵(

有没有大佬知道哪里写挂了嘛


by ___A__ @ 2023-08-31 14:55:13

@Birdly 线段树下标只能从1开始 集体偏移罢


by ___A__ @ 2023-08-31 14:56:00

您这个写法我是确实没看懂 可以参考一下我的 自认为还是写的很便于理解的

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+50;
int a[N],l,r,dp[N],n,inf;
struct segtree{
    int l,r,num;
}t[N*4];
void build(int x,int l,int r){
    t[x].l=l,t[x].r=r;
    if(l==r){
        return;
    }
    int mid=(l+r)/2;
    build(x*2,l,mid),build(x*2+1,mid+1,r);
}
int query(int x,int l,int r){
    if(l>r){
        return inf;
    }
    if(t[x].l>=l&&t[x].r<=r){
        return t[x].num;
    }
    int mid=(t[x].l+t[x].r)/2,ret=inf;
    if(l<=mid){
        ret=max(ret,query(x*2,l,r));
    }
    if(r>mid){
        ret=max(ret,query(x*2+1,l,r));
    }
    return ret;
}
void modify(int x,int idx,int num){
    if(t[x].l==t[x].r){
        t[x].num=num;
        return;
    }
    int mid=(t[x].l+t[x].r)/2;
    if(idx<=mid){
        modify(x*2,idx,num);
    }
    else{
        modify(x*2+1,idx,num);
    }
    t[x].num=max(t[x*2].num,t[x*2+1].num);
}
int main(){
    cin>>n>>l>>r;
    for(int i=1;i<=n+1;i++){
        cin>>a[i];
    }
    memset(dp,128,sizeof(dp));
    inf=dp[1],dp[1]=0;
    build(1,1,n+r+1);
    for(int i=2;i<=n+r+1;i++){
        dp[i]=query(1,max(1,i-r),i-l)+a[i],modify(1,i,dp[i]);
    }
    cout<<*max_element(dp+n+2,dp+n+r+2);
}

|