Codeforces-1487 E. Cheap Dinner(线段树优化DP)

在这里插入图片描述

思路:
定义 d p [ i ] [ j ] dp[i][j] dp[i][j]代表第 i i i次用餐中,选到了第 j j j个物品能得到的最小价值和。

就是每一层维护的dp数组用线段树表示,那么限制就是这一层的每个数与之前一层有一些数不能匹配,那么限制就是这一层的每个数与之前一层有一些数不能匹配。

不能匹配的数将数组划分为了很多区间,转移就是你在这些区间中之间取最小值加上当前这个数的权值

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>;
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 7;
const int mod = 1e9 + 7;
typedef long long ll;
struct Tree {int l,r;int mi,lazy;
}f[5][maxn << 2];
int a[5][maxn],A[maxn];
pair<int,int>b[5][maxn];
void pushdown(Tree* t,int i) {if(t[i].lazy != 1e9) {t[i * 2].lazy = min(t[i].lazy,t[i * 2].lazy);t[i * 2 + 1].lazy = min(t[i].lazy,t[i * 2 + 1].lazy);t[i * 2].mi = min(t[i].lazy,t[i * 2].mi);t[i * 2 + 1].mi = min(t[i].lazy,t[i * 2 + 1].mi);t[i].lazy = 1e9;}
}
void pushup(Tree* t,int i) {t[i].mi = min(t[i * 2].mi,t[i * 2 + 1].mi);
}
void build(Tree* t,int i,int l,int r) {t[i].l = l;t[i].r = r;t[i].lazy = 1e9;if(l == r) {t[i].mi = A[l];return;}int m = (l + r) >> 1;build(t,i * 2,l,m);build(t,i * 2 + 1,m + 1,r);pushup(t,i);
}
int query(Tree* t,int i,int x,int y) {if(x > y) return 1e9;if(x <= t[i].l && t[i].r <= y) {return t[i].mi;}pushdown(t,i);int m = (t[i].l + t[i].r) >> 1;int ans = 1e9;if(x <= m) ans = min(ans,query(t,i * 2,x,y));if(y > m) ans = min(ans,query(t,i * 2 + 1,x,y));return ans;
}
void update(Tree* t,int i,int x,int y,int v) {if(x > y) return;if(x <= t[i].l && t[i].r <= y) {t[i].mi = min(t[i].mi,v);t[i].lazy = min(t[i].lazy,v);return;}pushdown(t,i);int m = (t[i].l + t[i].r) >> 1;if(x <= m) update(t,i * 2,x,y,v);if(y > m) update(t,i * 2 + 1,x,y,v);pushup(t,i);
}int main() {int n[5];for(int i = 1;i <= 4;i++) scanf("%d",&n[i]);for(int i = 1;i <= 4;i++) {for(int j = 1;j <= n[i];j++) {scanf("%d",&a[i][j]);if(i == 1) A[j] = a[i][j];else A[j] = 1e9;}build(f[i],1,1,n[i]);}int m[5];for(int i = 2;i <= 4;i++) {scanf("%d",&m[i]);vector<int>G[maxn];for(int j = 1;j <= m[i];j++) {int x,y;scanf("%d%d",&x,&y);G[y].push_back(x);}for(int j = 1;j <= n[i];j++) {if(G[j].size() == 0) {int mi = query(f[i - 1],1,1,n[i - 1]);if(mi == 1e9) continue;update(f[i],1,j,j,mi + a[i][j]);} else {sort(G[j].begin(),G[j].end());G[j].push_back(n[i - 1] + 1);int pre = 0; //上一个不合法位置for(int q = 0;q < G[j].size();q++) {int v = G[j][q]; //下一个不合法位置int mi = query(f[i - 1],1,pre + 1,v - 1);pre = v;if(mi == 1e9) {continue;}update(f[i],1,j,j,mi + a[i][j]);}}}}int ans = query(f[4],1,1,n[4]);if(ans == 1e9) printf("-1\n");else printf("%d\n",ans);return 0;
}