[差分] [树上问题] P10174 Great Segments 题解
考虑合法区间的判定。先单调栈求出
对于一段区间
于是可以得到
考虑优化,将差分标记拆为加法和减法,尝试对于
由于每个
问题被转化为树上问题,对于加标记,可以快速计算得出,记
对于减标记,考虑递推求解,记
最后考虑
时间复杂度
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int n, k, a[N], stk[N], st, d[N], nxt[N];
vector<int> to[N];
long long ans[N];
inline void init(int u){
if(st - k + 1 > 0) --d[stk[st - k + 1]];
stk[++st] = u; int stt = st;
for(auto v : to[u])
st = stt, init(v);
}
inline void dfs(int u, int dep){
ans[u] += min(dep, k) - 1;
for(auto v : to[u]){
dfs(v, dep + 1);
d[u] += d[v] + 1;
}
ans[u + 1] -= d[u];
}
signed main(){
cin >> n >> k;
for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
for(int i = n; i >= 1; --i){
while(st && a[stk[st]] <= a[i]) --st;
if(st) nxt[i] = stk[st], to[stk[st]].push_back(i);
stk[++st] = i;
}
for(int i = 1; i <= n; ++i)
if(!nxt[i]) st = 0, init(i), dfs(i, 1);
for(int i = 1; i <= n; ++i)
ans[i] += ans[i - 1], printf("%lld\n", ans[i]);
return 0;
}