CF2150C 思路分享(dp,线段树)
https://codeforces.com/problemset/problem/2150/C
题意概述
共有 \(n\) 个物品,每个物品有一个价值 \(V_i\)。总共进行 \(n\) 轮,每轮由 \(A\) 或 \(B\) 拿物品,每个人都有一个偏好序列 \(a,b\),他们每次会拿偏好序列中第一个还存在的物品。求最后 \(A\) 所拿物品价值总和的最大值。
\(1\le n \le 2\times 10^5\)。
思路
首先先分析 \(A\) 拿物品的序列怎么样是合法的。
假如 \(a\) 序列为 \(1,2,3,4,5\),如果 \(A\) 想拿 \(1\) 和 \(4\) 号物品,那么在 \(b\) 中,\(2\) 和 \(3\) 号物品的顺位必须比 \(4\) 高。也就是前面所有不拿的物品在 \(b\) 的顺位都比 \(a_i\) 高。
这样就想到用双指针维护所有不拿的物品在 \(b\) 中的最大下标。预处理出 \(ord_i\) 为 \(i\) 号元素对应 \(b\) 中的下标,\(A\) 想拿 \(a_i\),此时指针必须 \(\lt ord_{a_i}\);如果不拿 \(a_i\),更新指针,与 \(ord_{a_i}\) 取最大值。
考虑 \(dp\),\(dp[i][j]\) 表示处理到 \(a\) 中第 \(i\) 个元素,此时指针在 \(j\)。
记 \(pos = ord_{a_i}\)。
-
如果不选 \(a_i\),所有 \(j\lt pos\) 的状态都被转移到 \(j=pos\) 的位置,\(j\gt pos\) 的状态不变。
-
如果选 \(a_i\),所有 \(j\lt pos\) 的状态都加上 \(V_{a_i}\)。
可以发现,如果不选 \(a_i\),所有 \(j\lt pos\) 的状态都会被设为不可达,所以用选 \(a_i\) 的情况直接加上 \(V_{a_i}\) 一定更优。
转移过程需要用线段树维护区间查询和区间加法,同时需要 \(j=0\) 的状态。
时间复杂度 \(\mathcal{O}(n\log n)\)。
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 9e18;
class segmentTree{
public:
class node{
public:
ll mx = -INF;
ll lazy = 0;
};
int n;
vector<node> seg;
segmentTree(int _n){
n = _n;
seg = vector<node>(4*n+1);
}
node merge(node p1,node p2){
node temp;
temp.mx = max(p1.mx,p2.mx);
return temp;
}
void build(vector<ll>& a){
build(1,1,n,a);
}
void build(int rt,int l,int r,vector<ll>& a){
if (l==r){
return;
}
int mid = l+r >> 1;
build(rt<<1,l,mid,a);
build(rt<<1|1,mid+1,r,a);
seg[rt] = merge(seg[rt<<1],seg[rt<<1|1]);
}
void push_down(int rt,int l,int r){
if (seg[rt].lazy==0) return;
seg[rt<<1].mx += seg[rt].lazy;
seg[rt<<1].lazy += seg[rt].lazy;
seg[rt<<1|1].mx += seg[rt].lazy;
seg[rt<<1|1].lazy += seg[rt].lazy;
seg[rt].lazy = 0;
}
void update(int pos,ll val){
update(1,1,n,pos,val);
}
void update(int rt,int l,int r,int pos,ll val){
if (l==r){
seg[rt].mx = max(seg[rt].mx,val);
return;
}
int mid = l+r >> 1;
push_down(rt,l,r);
if (pos<=mid){
update(rt<<1,l,mid,pos,val);
}
else{
update(rt<<1|1,mid+1,r,pos,val);
}
seg[rt] = merge(seg[rt<<1],seg[rt<<1|1]);
}
void update_range(int x,int y,ll val){
update_range(1,1,n,x,y,val);
}
void update_range(int rt,int l,int r,int x,int y,ll val){
if (r<x || l>y){
return;
}
if (x<=l && y>=r){
seg[rt].mx += val;
seg[rt].lazy += val;
return;
}
int mid = l+r >> 1;
push_down(rt,l,r);
update_range(rt<<1,l,mid,x,y,val);
update_range(rt<<1|1,mid+1,r,x,y,val);
seg[rt] = merge(seg[rt<<1],seg[rt<<1|1]);
}
node query(int pos){
if (pos<1 || pos>n) return {};
return query(1,1,n,pos);
}
node query(int rt,int l,int r,int pos){
if (l==r){
return seg[rt];
}
int mid = l+r >> 1;
push_down(rt,l,r);
if (pos<=mid){
return query(rt<<1,l,mid,pos);
}
else{
return query(rt<<1|1,mid+1,r,pos);
}
}
node query_range(int l,int r){
if (l<1 || l>n || r<1 || r>n || l>r) return {};
return query_range(1,1,n,l,r);
}
node query_range(int rt,int l,int r,int x,int y){
if (r<x || l>y){
return {};
}
if (x<=l && y>=r){
return seg[rt];
}
int mid = l+r >> 1;
push_down(rt,l,r);
return merge(query_range(rt<<1,l,mid,x,y),query_range(rt<<1|1,mid+1,r,x,y));
}
bool is_valid(int rt,int l,int r,int x,int y,ll val){
if (r<x || l>y) return false;
//
return false;
}
int first_valid(int l,int r,ll val){
if (l>r) return -1;
return first_valid(1,1,n,l,r,val);
}
int first_valid(int rt,int l,int r,int x,int y,ll val){
if (!is_valid(rt,l,r,x,y,val)) return -1;
if (l==r){
return l;
}
int mid = l+r >> 1;
push_down(rt,l,r);
int res = first_valid(rt<<1,l,mid,x,y,val);
if (res!=-1){
return res;
}
return first_valid(rt<<1|1,mid+1,r,x,y,val);
}
int last_valid(int l,int r,ll val){
if (l>r) return -1;
return last_valid(1,1,n,l,r,val);
}
int last_valid(int rt,int l,int r,int x,int y,ll val){
if (!is_valid(rt,l,r,x,y,val)) return -1;
if (l==r){
return l;
}
int mid = l+r >> 1;
push_down(rt,l,r);
int res = last_valid(rt<<1|1,mid+1,r,x,y,val);
if (res!=-1){
return res;
}
return last_valid(rt<<1,l,mid,x,y,val);
}
};
void solve(){
int n;
cin >> n;
vector<ll> V(n+1);
for (int i=1;i<=n;i++){
cin >> V[i];
}
vector<int> a(n+1),b(n+1);
for (int i=1;i<=n;i++){
cin >> a[i];
}
vector<int> ord(n+1);
for (int i=1;i<=n;i++){
cin >> b[i];
ord[b[i]] = i;
}
segmentTree sg(n+1);
sg.update(1,0);
for (int i=1;i<=n;i++){
int pos = ord[a[i]];
ll cur = sg.query_range(1,pos).mx;
sg.update(pos+1,cur);
sg.update_range(1,pos,V[a[i]]);
}
cout << sg.seg[1].mx << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号