CF1998E2 sol
Eternatis
·
·
题解
考虑 E1 的分治解法,其过程相当于一棵笛卡尔树,而笛卡尔树可以通过维护右链 $O(n)$ 建,于是考虑动态维护需要的信息。
注意到在构造笛卡尔树时,一个点一旦被作为某个点的左子树,其信息就**不再改变**,即维护的右链上,每个点的左子树答案确定,考虑对当前栈内每个点,维护**根与左子树**的权值和与贡献和,记作 $sum$ 与 $w$ ,这样从栈中删除点并挂到左儿子上的过程是简单的。
现在考虑加点时,对栈中元素 $sum$ 值的影响。
考虑这相当于对插入的元素到根的链进行链加,但注意到每次插入元素时,其最终会作为右链的结尾,于是可以直接维护一个全局加标记 $tag$ ,再记录一个 $r$ 表示当前元素还需要加多少变为合法,即子树权值和不小于父节点权值。
用一个队列维护上述过程,每次判断队头是否合法,若已经合法就出队,这样每个元素只会入队出队一次。注意初始化每个元素的 $r$ 时消去当前标记的影响即可。
最后只剩求答案的部分,考虑当前队头,即第一个不合法位置,因为每个点都维护了左子树的信息,所以当前的答案相当于栈内元素 $w$ 值的前缀和,在将元素插入栈内时维护即可。
注意因为会从栈顶删数,队列里可能会存在不在栈中的元素,开个数组记录一下就好了。
code:
```cpp
#include<bits/stdc++.h>
using namespace std;
#define N 1000010
#define int long long
#define db long double
#define pii pair<int,int>
#define st first
#define ed second
#define mkp make_pair
#define pb push_back
#define eps 1e-9
#define mod 998244353
#define mod2 1000000007
#define bs 13131
#define bs2 131
#define INF 0x3f3f3f3f3f3f3f3f
#define il inline
#define vi vector<int>
#define ins insert
#define umap unordered_map
#define uset unordered_set
#define R(x) x.begin(),x.end()
#define B(x) x.begin()
#define E(x) x.end()
#define lb lower_bound
#define ub upper_bound
#define vi vector<int>
il int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int T=1,n,m,q,k;
int s[N],sum[N],w[N]; // sum 和 w 记录栈内左子树信息
int stk[N],top;
int sm[N],val[N]; // sm 与 tag 对应,用来维护栈内元素是否合法,val 记录栈内贡献前缀和
bool instk[N]; // instk 记录是否在栈内,防止队列未及时清空
il void solve(){
n=read();m=read();
for(int i=1;i<=n;i++)
s[i]=read(),sum[i]=w[i]=sm[i]=val[i]=instk[i]=0;
top=0;
int tag=0;
queue<int> q;
for(int i=1;i<=n;i++){
int k=top;
while(k&&s[stk[k]]<s[i])k--;
sum[i]=s[i],w[i]=1;
while(top>k+1){ // 合并栈顶到当前节点
if(sum[stk[top]]>=s[stk[top-1]])
w[stk[top-1]]+=w[stk[top]];
sum[stk[top-1]]+=sum[stk[top]];
instk[stk[top]]=0;
top--;
}
if(top>k){ // 特判最后一个元素是否合并(可能出现当前元素加入即为栈顶的情况)
if(sum[stk[k+1]]>=s[i])
w[i]+=w[stk[k+1]];
sum[i]+=sum[stk[k+1]];
instk[stk[k+1]]=0;
}
stk[k+1]=i;top=k+1;
instk[i]=1;
tag+=s[i];
sm[i]=s[stk[top-1]]+tag-sum[i]; // 消除已有 tag 的影响
val[i]=val[stk[top-1]]+w[i];
q.push(i);
while(!q.empty()){
int x=q.front();
if(tag>=sm[x]||!instk[x])q.pop();
else break;
}
if(q.empty())printf("%lld ",val[i]);
else {
int p=q.front();
printf("%lld ",val[p]-w[p]);
}
}
puts("");
}
signed main(){
T=read();
while(T--)solve();
return 0;
}
```