2026 ICPC Asia EC 网络预选赛第一场 N 题思路分享(二维偏序,二维树状数组,dp)
题目链接
题意
给定长度为 \(n\) 的序列,每个位置有红、黄、蓝棋子各至多一枚.
若一段连续区间内,红棋子数量均不少于黄棋子数量和蓝棋子数量,则称该区间合法,求所有合法区间长度之和的最大值.
\(1\le n \le 10^6\).
思路
考虑 \(dp\),令 \(dp_i\) 为处理到 \(i\) 时的最大合法区间长度和,转移如下:
\[dp_i = \max(dp_{i-1},\max_{j\lt i}(dp_j+i-j))
\]
其中,必须满足区间 \([j+1,i]\) 合法,可以用前缀和刻画,即满足:
\[\begin{cases}
preR_i-preY_i \ge preR_j-preY_j \\
preR_i-preB_i \ge preR_j-preB_j
\end{cases}
\]
这是一个二维偏序约束,使用二维树状数组维护 \(\max_{j\lt i}(dp_j-j)\) 即可.
二维树状数组实现有几点需要注意:
-
第二维不需要离散化.
-
提前获取参与更新和查询的点对 \((x,y)\),需要把 \(y\) 传给所有 \(x\) 往后跳 \(lowbit\) 的位置.
-
查询时二分的坐标不一定存在.
时间复杂度 \(\mathcal{O}(n\log^2 n)\).
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int INF = 1e9;
struct fenwick{
int n;
vector<vector<int>> pos,mx;
fenwick(int _n){
n = _n;
pos.assign(n+1,{-INF});
mx.resize(n+1);
}
void build(vector<pair<int,int>>& vec){
for (auto& [x,y]:vec){
for (int i=x;i<=n;i+=i&-i){
pos[i].push_back(y);
}
}
for (int i=1;i<=n;i++){
sort(pos[i].begin()+1,pos[i].end());
pos[i].erase(unique(pos[i].begin()+1,pos[i].end()),pos[i].end());
int m = pos[i].size()-1;
mx[i].assign(m+1,-INF);
}
}
void update(int x,int y,int val){
for (int i=x;i<=n;i+=i&-i){
int m = pos[i].size()-1;
int rk = lower_bound(pos[i].begin()+1,pos[i].end(),y)-pos[i].begin();
for (int j=rk;j<=m;j+=j&-j){
mx[i][j] = max(mx[i][j],val);
}
}
}
int query(int x,int y){
int res = -INF;
for (int i=x;i>=1;i-=i&-i){
int m = pos[i].size()-1;
int rk = upper_bound(pos[i].begin()+1,pos[i].end(),y)-pos[i].begin()-1;
for (int j=rk;j>=1;j-=j&-j){
res = max(res,mx[i][j]);
}
}
return res;
}
};
void solve(){
int n;
cin >> n;
vector<array<int,3>> pre(n+1,{0,0,0});
for (int i=1;i<=n;i++){
for (int j=0;j<3;j++){
int x;
cin >> x;
pre[i][j] = pre[i-1][j]+x;
}
}
vector<pair<int,int>> wait(n+1);
wait[0] = {0,0};
vector<int> uni{-INF};
uni.push_back(0);
for (int i=1;i<=n;i++){
wait[i] = {pre[i][0]-pre[i][1],pre[i][0]-pre[i][2]};
uni.push_back(pre[i][0]-pre[i][1]);
}
sort(uni.begin()+1,uni.end());
uni.erase(unique(uni.begin()+1,uni.end()),uni.end());
int m = uni.size()-1;
for (int i=0;i<=n;i++){
wait[i].first = lower_bound(uni.begin()+1,uni.end(),wait[i].first)-uni.begin();
}
fenwick fw(m);
fw.build(wait);
fw.update(wait[0].first,wait[0].second,0);
vector<int> dp(n+1);
for (int i=1;i<=n;i++){
dp[i] = max(dp[i-1],i+fw.query(wait[i].first,wait[i].second));
fw.update(wait[i].first,wait[i].second,dp[i]-i);
}
cout << dp[n] << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号