相当好的一道题。

直接贪心可以做到 \(O(n^2\log n)\),但是没有什么优化空间。

注意到原问题是一个二分图匹配问题,考虑使用 Hall 定理进行转化,设蚂蚁是左部点,方糖是右部点,那么有:

\(ans=sumant-\max \limits_{(l_i,r_i)互不相交} (ant(l_i,r_i)-sugar(l_i-L,r_i+L))\)

\(r_i\)\(l_{i+1}\) 之间的距离一定大于等于 \(2L\),否则可以合并使得其值更大(后面要考)。


注意到是一个区间和的形式,转化为前缀和,设:\(p_i=-ant_{i-1}+sugar_{i-L},q_i=ant_i-sugar_{i+L}\),那么答案相当于交替选 \(p,q\) 的和的最大值。(这里的交替是,\(p\) 后面可以立即接上 \(q\),但是 \(q\) 和下一个 \(p\) 必须距离大于等于 \(1\),因为我们的式子里要求 \([l,r]\) 不能相交)

可以想到动态 DP,\(f_{i,0/1,0/1}\) 表示在线段树 \(i\) 所代表的区间中,最左边是 \(p/q\),最右边是 \(p/q\) 的最大价值。


考虑修改,对于修改 \(ant_x\),设增加了 \(y\),那么改变相当于:

  • \(\forall i\in[x+1,\infty],p_i:=p_i-y\)

  • \(\forall i\in [x,\infty],q_i:=q_i+y\)

区间修改?似乎不能直接对着 dp 值进行修改。

注意力惊人地,我们发现两个操作修改区间几乎相同。其实对于 \([x+1,\infty]\) 中的修改,\(f_{i,0/1,0/1}\) 的最优策略是没有改变的,因为对一个 dp 值加/减几个 \(y\) 已经在 \((0/1,0/1)\) 里面体现出来了,所以我们可以直接在线段树上打标记。

剩下 \([x,x]\) 的单点修改即可,

对于修改 \(sugar_x\),设增加了 \(y\),那么改变相当于:

  • \(\forall i\in[x+L+1,\infty],p_i:=p_i+y\)
  • \(\forall i\in[x-L,\infty],q_i:=q_i-y\)

此时相同部分我们依然可以照葫芦画瓢,但是对于 \([x-L,x+L]\) 也要修改,此时是一个区间的形式,暴力修改的话时间会炸掉。

注意到区间长度为 \(2L\),也就意味着这中间的可能贡献到上面的 dp 值实际上至多只选择了一个 \(r\),我们只需要将这个区间所有 \((0,1)\)\((1,0)\)\((1,1)\) 加上 \(y\) 即可。

最后还有一点问题,我们要求 \(q\) 后面不能接上 \(p\),所以对于 \(u\) 节点所代表的区间满足 \(l=r\) 的时候 \(f_{u,1,0}=-\infty\)


#include<bits/stdc++.h>
using namespace std;
#define ls u<<1
#define rs u<<1|1
#define N 500005
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3f 
struct node{int op,x,y;};
int n,m,sz,b[N];
ll f[N<<2][2][2],t1[N<<2],t2[N<<2],sum;//0 左端点,1 右端点;t1 共改;t2 r 加 
//注意正负 正负 正负 正负 正负 正负 正负 正负 正负 正负 正负 正负 正负 正负 正负 正负 
node a[N];
inline void pull(int u){
	for(int l=0;l<2;l++)for(int r=0;r<2;r++){
		f[u][l][r]=max(f[ls][l][r],f[rs][l][r]);
		for(int k=0;k<2;k++)f[u][l][r]=max(f[u][l][r],f[ls][l][k]+f[rs][k^1][r]);
	}
}
inline void pushtag(int u,ll tag1,ll tag2){
	t1[u]+=tag1;t2[u]+=tag2;
	f[u][0][0]+=tag1;f[u][1][1]-=tag1;
	f[u][0][1]+=tag2;f[u][1][0]+=tag2;f[u][1][1]+=tag2;
}
inline void push(int u){
	if(t1[u]||t2[u])
		pushtag(ls,t1[u],t2[u]),pushtag(rs,t1[u],t2[u]),t1[u]=t2[u]=0;
}
inline void upd(int u,int l,int r,int L,int R,ll x,ll y){
	if(L<=l&&r<=R)return pushtag(u,x,y);
	push(u);int m=(l+r)>>1;
	if(m>=L)upd(ls,l,m,L,R,x,y);
	if(m<R)upd(rs,m+1,r,L,R,x,y);
	pull(u);
}
inline void upd(int L,int R,ll x,ll y){if(L<=R)upd(1,1,sz,L,R,x,y);}
void build(int u,int l,int r){
	if(l==r)f[u][1][0]=-inf;
	if(l==r)return;
	int m=(l+r)>>1;
	build(ls,l,m),build(rs,m+1,r);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d%d%d",&a[i].op,&a[i].x,&a[i].y),b[++sz]=a[i].x;
	sort(b+1,b+1+sz);sz=unique(b+1,b+1+sz)-b-1;
	build(1,1,sz);
	for(int i=1;i<=n;i++){
		if(a[i].op==1){
			sum+=a[i].y;
			int p=a[i].x+1,q=a[i].x;
			p=lower_bound(b+1,b+1+sz,p)-b;
			q=lower_bound(b+1,b+1+sz,q)-b;
			upd(p,sz,-a[i].y,0);
			upd(q,p-1,0,a[i].y);
		}else{
			int p=a[i].x+m+1,q=a[i].x-m;
			p=lower_bound(b+1,b+1+sz,p)-b;
			q=lower_bound(b+1,b+1+sz,q)-b;
			upd(p,sz,a[i].y,0);
			upd(q,p-1,0,-a[i].y);
		}
		printf("%lld\n",sum-max(0ll,f[1][0][1]));
	}
}