CCO2023 Real Mountains
P10067 [CCO2023] Real Mountains
设
容易猜测一个结论:每次选择
假设这个并列最小值为
最优操作方案是:对于左端点,我们找到二元组
那么可以先进行一次
所以我们得到了一个暴力做法:遍历整个数组,提取出若干个 还需增加的并列最小值,找到两个二元组进行更新。复杂度爆炸。
考虑离散化。若出现在
现在问题转化为了一个序列
- 查询前缀/后缀中大于某值的最小值;
- 一个抽象的修改操作。
发现很难处理修改。然而仔细分析可以发现修改是不需要的。因为根据上述算法,不可能存在两个位置
const int N = 1e6 + 10;
const ll P = 1e6 + 3;
int n;
ll a[N], b[N];
tuple<ll, int, int> q[N*2];
ll ans;
ll Sum(ll x, ll y){
return (y * (y-1) / 2 % P - x * (x-1) / 2 % P + P) % P;
}
int t[N*100], ls[N*100], rs[N*100];
int rtl[N], rtr[N], cnt;
int add(int p, int l, int r, int x){
++ cnt;
tie(t[cnt], ls[cnt], rs[cnt]) = tie(t[p], ls[p], rs[p]);
p = cnt;
if(l == r){
++ t[p];
} else {
int mid = l + r >> 1;
if(x <= mid){
ls[p] = add(ls[p], l, mid, x);
} else {
rs[p] = add(rs[p], mid+1, r, x);
}
t[p] = t[ls[p]] + t[rs[p]];
}
return p;
}
int qry(int p, int l, int r, int ge){
if(t[p] == 0 || r <= ge){
return -1;
} else if(l == r){
return l;
} else {
int mid = l + r >> 1, tmp;
if((tmp = qry(ls[p], l, mid, ge)) > ge){
return tmp;
} else {
return qry(rs[p], mid+1, r, ge);
}
}
}
int qrl(int x, int mn){
return qry(rtl[x], 1, 1e9, mn);
}
int qrr(int x, int mn){
return qry(rtr[x], 1, 1e9, mn);
}
void solve(){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%lld", &a[i]);
q[i] = { a[i], i, -1 };
}
ll mx = 0;
rtl[0] = ++ cnt;
for(int i = 1; i <= n; ++ i){
mx = max(mx, a[i]);
rtl[i] = add(rtl[i-1], 1, 1e9, a[i]);
b[i] = mx;
}
mx = 0;
rtr[n+1] = ++ cnt;
for(int i = n; i >= 1; -- i){
mx = max(mx, a[i]);
b[i] = min(b[i], mx);
rtr[i] = add(rtr[i+1], 1, 1e9, a[i]);
q[i+n] = { b[i], i, 1 };
}
sort(q + 1, q + n + n + 1);
set<int> st;
for(int i = 1; i < n + n; ++ i){
if(get<2>(q[i]) == -1){
st.insert(get<1>(q[i]));
} else {
st.erase(get<1>(q[i]));
}
if(get<0>(q[i]) != get<0>(q[i+1]) && st.size()){
ll fr = get<0>(q[i]), to = get<0>(q[i+1]);
ll l = *st.begin(), r = *st.rbegin(), k = st.size();
ll oo = qrl(l, fr), pp = qrr(l, fr), qq = qrl(r, fr), rr = qrr(r, fr);
ll p = qrl(l, fr), q = qrr(r, fr);
if(k == 1){
ans += Sum(fr, to);
ans += (oo + pp) % P * (to - fr) % P;
} else {
ans += (oo + rr + min(pp, qq) + k + k - 3) % P * (to - fr) % P;
ans += 3 * (k - 1) % P * Sum(fr, to) % P;
}
ans %= P;
}
}
printf("%lld\n", ans);
}