CF1266E Solution

题目链接

题解

容易发现,\(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;
}
posted @ 2021-02-23 19:56  violet_holmes  阅读(48)  评论(0编辑  收藏  举报