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;
}
标签:const,int,TT,hard,tr,Up,long,Start,define
From: https://www.cnblogs.com/basicecho/p/17224280.html