D2. Hot Start Up (hard version)

D2. Hot Start Up (hard version)

思路

有两种方法:
1.求最小不相交的区间的和,但是需要偏移一下,这样才能保证区间一定不相交
2.根据D1中dp的式子中可以看出,只有1个点是进行了多次更新,其他的都是直接在原来的基础上进行加上对应的值。

代码1

/*
对于连续出现的数,直接将他减少的值加上就可以了
因为有两个cpu,所以可以看成一个是一直在工作,另外一个是用来等待的
处理一下是否需要等待这个数就可以了
也就是最大不相交区间问题

1 2 1 2
但是区间可能会出现相交的情况,但是最多只会重复一个点,所以将区间的右端点进行移动一下就可以了
*/
#include <bits/stdc++.h>
using namespace std;
const int M = 3e5 + 5;
#define endl '\n'
#define int long long
using pii = pair<int, int>;

int a[M],b[M],cold[M],hot[M];
int dp[M],pre[M],w[M];

void solve() {
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=m;i++)cin>>cold[i],b[i]=0;
    for(int i=1;i<=m;i++)cin>>hot[i];
    int sum=0;
    for(int i=1;i<=n;i++) {
        pre[i]=-1;
        sum+=(a[i]==a[i-1])?hot[a[i]]:cold[a[i]];
        if(b[a[i]]&&a[i]!=a[i-1]) {
            pre[i-1]=b[a[i]];
            w[i-1]=cold[a[i]]-hot[a[i]];//为什么是存在上一个位置呢
        }
        b[a[i]]=i;
    }
    for(int i=1;i<=n;i++) {
        dp[i]=dp[i-1];
        if(pre[i]!=-1)dp[i]=max(dp[i],dp[pre[i]]+w[i]);
    }
    cout<<sum-dp[n]<<endl;
}

signed main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int TT; cin >> TT;
    while(TT--) {
        solve();
    }
    return 0;
}

代码2

/*
由d1可知道,f(i,j)全部都是直接由f(i,j-1)直接转移过来的
只有上一个选择接在j后面,也就是保留a[i-1]的,才是在所有的里面取出一个最小值
所以可以由线段树来进行维护dp的变化
*/
#include <bits/stdc++.h>
using namespace std;
const int M = 3e5 + 5;
#define endl '\n'
#define int long long
const int inf = 1e18;

#define mn(u) tr[u].mn
#define la(u) tr[u].la
#define ul u<<1
#define ur u<<1|1

struct node {
    int l,r,la,mn;
}tr[M<<2];

void pu(int u) {
    mn(u)=min(mn(ul),mn(ur));
}

void build(int u,int l,int r) {
    tr[u]={l,r,0,inf};
    if(l==r)return ;
    int mid=(l+r)/2;
    build(ul,l,mid);
    build(ur,mid+1,r);
}

void pd(int u) {
    if(la(u)==0)return;
    la(ul)+=la(u);
    la(ur)+=la(u);
    mn(ul)+=la(u);
    mn(ur)+=la(u);
    la(u)=0;
}

int query(int u,int l,int r) {
    if(tr[u].l>=l&&tr[u].r<=r)return mn(u);
    if(tr[u].l>r||tr[u].r<l)return inf;
    pd(u);
    return min(query(ul,l,r),query(ur,l,r));
}

void add(int u,int l,int r,int v) {
    if(tr[u].l>=l&&tr[u].r<=r) {
        la(u)+=v;
        mn(u)+=v;
        return;
    }
    if(tr[u].l>r||tr[u].r<l)return;
    pd(u);
    add(ul,l,r,v);
    add(ur,l,r,v);
    pu(u);
}

void up(int u,int pos,int v) {
    if(tr[u].l==tr[u].r&&tr[u].l==pos) {
        mn(u)=min(mn(u),v);
        return ;
    }
    if(tr[u].l>pos||tr[u].r<pos)return;
    pd(u);
    up(ul,pos,v);
    up(ur,pos,v);
    pu(u);
}

int a[M],w1[M],w2[M];

void solve() {
    int n,m;
    cin>>n>>m;
    build(1,0,m);
    up(1,0,0);//先将0这个点置为0
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=m;i++)cin>>w1[i];
    for(int i=1;i<=m;i++)cin>>w2[i];
    for(int i=1;i<=n;i++) {
        int tmp=min(query(1,0,m)+w1[a[i]],query(1,a[i],a[i])+w2[a[i]]);//所有的点查询是不受影响的
        //cout<<query(1,a[i-1],a[i-1])<<endl;
        add(1,0,m,a[i]==a[i-1]?w2[a[i]]:w1[a[i]]);//对所有的人进行更新就可以了
        up(1,a[i-1],tmp);//然后对这个点进行单独的更新
    }
    cout<<query(1,0,m)<<endl;
}

signed main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int TT; cin >> TT;
    while(TT--) {
        solve();
    }
    return 0;
}
posted @ 2023-03-16 21:40  basicecho  阅读(72)  评论(0)    收藏  举报