题解
容易发现,\(s_i,t_i\)对于\(a_{u_i}+1\)的操作影响并不大,因为\(t_i<a_{s_i}\)无论如何都会触发该操作。而对于\(s_j=s_i,t_j=t_i,j<i\)的三元组\(s_j,t_j,u_j\)只需将\(a_{u_j}-1\)即可。我们需要在\(logn\)的时间内进行上述\(+1,-1\)的操作,并查询最终\(a\)数组的和,容易想到树状数组。为了方便查询,定义树状数组\(t_i\)表示\([a_1,a_i]\)所需的回合数。此外,注意到三元组的贡献和可能会\(>a_i\),这时所需回合数仍为\(0\),而按照上述作法会使其产生负数。因此需另设\(qwq\)数组进行单点修改操作,处理回合数\(<0\)的情况,而在树状数组添加操作中特判保证\(a_i\ge 1\)。
AC代码
#include<bits/stdc++.h>
#define int long long
#define lowb(x) x&(-x)
#define m_p make_pair
using namespace std;
const int N=2e5+10;
int a[N],t[N],n,qwq[N];
map<pair<int,int>,int> mp;
int query(int x)
{
int ans=0;
while(x) {ans+=t[x]; x-=lowb(x);}
return ans;
}
void add(int x,int d)
{
if(!x) return;
d=max(d,query(x-1)-query(x));//为防止a[x]<0,需保证d>=-a[x]
while(x<=n) {t[x]+=d; x+=lowb(x);}
}
signed main()
{
int x,y,z,q;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
add(i,a[i]); qwq[i]=a[i];
}
scanf("%lld",&q);
while(q--)
{
scanf("%lld%lld%lld",&x,&y,&z);
//覆盖之前操作
int pre=mp[m_p(x,y)];
if(qwq[pre]>=0) add(pre,1);//<0的情况+1对回合数不产生影响,通过下方qwq[pre]++处理
//处理当前操作
add(z,-1); mp[m_p(x,y)]=z;
qwq[pre]++,qwq[z]--;
printf("%lld\n",query(n));//ans=a[1]~a[n]的回合数和
}
return 0;
}