• 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;
    }
    
  • 相关阅读:
    Linux 磁盘管理
    Linux 特殊权限及if语句
    Linux find命令
    MySQL索引知识介绍
    MySQL库表设计小技巧
    教你用SQL实现统计排名
    Truncate用法详解
    utf8字符集下的比较规则
    关于Aborted connection告警日志的分析
    MySQL DDL详情揭露
  • 原文地址:https://www.cnblogs.com/violetholmes/p/14437846.html
Copyright © 2020-2023  润新知