2020ICPC·小米 网络选拔赛第一场
E Phone Network
涉及算法:线段树维护dp,线段树上二分
思路:先考虑 \(n^2\) 的 \(dp\) ,\(dp[le][i]\) 表示当以 \(le\) 为 左端点时,包含数 \(1-i\) 的最小右端点,我们设 \(p_1, p_2, p_3....p_k\) 为所有数 \(i + 1\) 下标大于 \(le\) 的下标,所以 \(dp[le][i + 1] = max(dp[le][i], p_1)\) 。
容易发现 \(dp[1][i], dp[2][i], dp[3][i] .... dp[n][i]\) 一定是单调递增的,如果不存在结果则把值设为 \(inf\) ,又由于在已知 \(dp[le][i]\) 时, 计算 \(dp[le][i + 1]\) 只需要考虑 \(le\) 右边第一个 \(i + 1\) 的位置,所有可以用线段树区间覆盖操作来维护, 具体看代码。
#include <bits/stdc++.h>
using namespace std;
#define lc (rt << 1)
#define rc ((rt << 1) | 1)
#define fi first
#define se second
#define pb push_back
#define pii pair<int, int>
#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, r, l) for (int i = (r); i >= (l); --i)
#define PE(i, u) for (int i = head[u]; i != -1; i = edge[i].next)
typedef long long LL;
const int maxn = 1e6 + 20;
const int mod = 1e9 + 7;
int n, m;
vector<int> vec[maxn];
pii tree[maxn << 2];
int lazy[maxn << 2];
void PushUp(int rt){
tree[rt].fi = min(tree[lc].fi, tree[rc].fi);
tree[rt].se = min(tree[lc].se, tree[rc].se);
}
void PushDown(int rt, int le, int ri){
if(!lazy[rt]) return ;
int mid = (le + ri) >> 1;
tree[lc].fi = tree[rc].fi = lazy[rt];
tree[lc].se = lazy[rt] - mid;
tree[rc].se = lazy[rt] - ri;
lazy[lc] = lazy[rc] = lazy[rt];
lazy[rt] = 0;
return ;
}
int Query(int le, int ri, int L, int R, int val, int rt){
if(le == ri) {
if(tree[rt].fi < val) return le;
else return -1;
}
PushDown(rt, le, ri);
int mid = (le + ri) >> 1;
if(R > mid && tree[rc].fi < val) return Query(mid + 1, ri, L, R, val, rc);
if(L <= mid) return Query(le, mid, L, R, val, lc);
return -1;
}
void Update(int le, int ri, int L, int R, int val, int rt){
if(tree[rt].fi > val) return ;
if(L <= le && ri <= R){
tree[rt].fi = val;
tree[rt].se = val - ri;
lazy[rt] = val;
return ;
}
PushDown(rt, le, ri);
int mid = (le + ri) >> 1;
if(L <= mid) Update(le, mid, L, R, val, lc);
if(R > mid) Update(mid + 1, ri, L, R, val, rc);
PushUp(rt);
}
int ans[maxn];
int main(int argc, char const *argv[])
{
scanf("%d%d", &n, &m);
rep(i, 1, m) vec[i].push_back(0);
rep(i, 1, n){
int x;
scanf("%d", &x);
vec[x].push_back(i);
}
rep(i, 1, m){
int len = vec[i].size();
rep(j, 1, len - 1){
if(vec[i][j - 1] == vec[i][j]) continue;
int pos = Query(1, n, vec[i][j - 1] + 1, vec[i][j], vec[i][j], 1);
if(pos != -1){
Update(1, n, vec[i][j - 1] + 1, pos, vec[i][j], 1);
}
}
Update(1, n, vec[i][len - 1] + 1, n, mod, 1);
ans[i] = tree[1].se + 1;
}
rep(i, 1, m){
printf("%d ", ans[i]);
}
printf("\n");
return 0;
}