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;
}
posted @ 2026-05-20 16:41  kzssCCC  阅读(5)  评论(0)    收藏  举报