首页 > 其他分享 >AT_abc287_g [ABC287G] Balance Update Query 题解

AT_abc287_g [ABC287G] Balance Update Query 题解

时间:2024-03-05 19:13:00浏览次数:23  
标签:define idx re int 题解 Update -- abc287 op

分析

一眼分块。

用值域分块来维护。先把所有的值离散化,使得至于不大于 $n+q$。统计一下每个值的数量,每个块包含值的数量,每个块的价值和。修改值的时候先把原来值的数量,块包含的数量,块的价值剪掉被修改值的贡献,然后在新的值上面更新。修改数量直接改数量的变化贡献即可。

找前 $x$ 大的值之和从值域上限开始枚举,照常暴力散区间、整块。

复杂度 $O(q \sqrt{V})$。

注:离散化之后注意贡献是离散化之前的值,要还原。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define re register
#define il inline

const int N=2e5+10;
int n,q;
int a[N],b[N];
struct node{
	int op,x,y;
}Q[N];
int cnt[N<<1],sum[N],val[N],len;
int y[N<<1],c[N<<1],idx;

il int get(int x){return (x-1)/len+1;}
il int query(int x){
	int bl=get(1),br=get(idx);
	int ans=0;
	if(bl==br){
		for(re int i=idx;i>=1;--i){
			if(x<=cnt[i]){ans+=x*y[i];return ans;}
			else{ans+=cnt[i]*y[i],x-=cnt[i];}
		}
		if(x==0) return ans;
		return -1;
	}
	for(re int i=idx;i>=(br-1)*len+1;--i){
		if(x<=cnt[i]){ans+=x*y[i];return ans;}
		else{ans+=cnt[i]*y[i],x-=cnt[i];}
	}
	for(re int bk=br-1;bk>=bl+1;--bk){
		if(x<=sum[bk]){
			for(re int i=bk*len;i>=(bk-1)*len+1;--i){
				if(x<=cnt[i]){ans+=x*y[i];return ans;}
				else{ans+=cnt[i]*y[i],x-=cnt[i];}
			}
			return -1;
		}
		else{ans+=val[bk],x-=sum[bk];}
	}
	for(re int i=bl*len;i>=1;--i){
		if(x<=cnt[i]){ans+=x*y[i];return ans;}
		else{ans+=cnt[i]*y[i],x-=cnt[i];}
	}
	if(x==0) return ans;
	return -1;
}
il void read(){
	cin>>n;
	for(re int i=1;i<=n;++i) cin>>a[i]>>b[i],c[++idx]=a[i];
	cin>>q;
	for(re int i=1;i<=q;++i){
		cin>>Q[i].op;
		if(Q[i].op==3) cin>>Q[i].x;
		else cin>>Q[i].x>>Q[i].y;
		if(Q[i].op==1) c[++idx]=Q[i].y;
	}
	sort(c+1,c+idx+1),idx=unique(c+1,c+idx+1)-(c+1);
	for(re int i=1,x;i<=n;++i) x=a[i],a[i]=lower_bound(c+1,c+idx+1,a[i])-c,y[a[i]]=x;
	for(re int i=1;i<=q;++i){
		if(Q[i].op==1){
			int x=Q[i].y;
			Q[i].y=lower_bound(c+1,c+idx+1,Q[i].y)-c;
			y[Q[i].y]=x;
		}
	}
	return ;
}
il void solve(){
	len=sqrt(idx);
	for(re int i=1;i<=n;++i){
		cnt[a[i]]+=b[i];
		sum[get(a[i])]+=b[i];
		val[get(a[i])]+=b[i]*y[a[i]];
	}
	for(re int i=1;i<=q;++i){
		if(Q[i].op==1){
			cnt[a[Q[i].x]]-=b[Q[i].x];
			sum[get(a[Q[i].x])]-=b[Q[i].x];
			val[get(a[Q[i].x])]-=b[Q[i].x]*y[a[Q[i].x]];
			
			a[Q[i].x]=Q[i].y;
			
			cnt[a[Q[i].x]]+=b[Q[i].x];
			sum[get(a[Q[i].x])]+=b[Q[i].x];
			val[get(a[Q[i].x])]+=b[Q[i].x]*y[a[Q[i].x]];			
		}
		else if(Q[i].op==2){
			cnt[a[Q[i].x]]+=(Q[i].y-b[Q[i].x]);
			sum[get(a[Q[i].x])]+=(Q[i].y-b[Q[i].x]);
			val[get(a[Q[i].x])]+=(Q[i].y-b[Q[i].x])*y[a[Q[i].x]];
			
			b[Q[i].x]=Q[i].y;
		}
		else if(Q[i].op==3){
			cout<<query(Q[i].x)<<"\n";
		}
	}
	return ;
}

signed main(){
	read(),solve();
	return 0;
}

标签:define,idx,re,int,题解,Update,--,abc287,op
From: https://www.cnblogs.com/harmisyz/p/18054677

相关文章

  • P8844 [传智杯 #4 初赛] 小卡与落叶 题解
    分析乱搞题。$1\len,m\le10^5$的时候就可以考虑乱搞了。发现每次操作$1$都会把上一次的操作$1$覆盖掉,那么第$i$个询问时树的颜色情况就是由前$1$个操作$1$决定。也就是说这个询问的内容变成了:在$x$为根的子树中,深度不小于$x'$的节点数量。$x'$是该操作$1$......
  • AT_abc287_g [ABC287G] Balance Update Query 题解2
    分析权值线段树。给每个节点赋一个值$val$和$a_i=val$的$b_i$之和。修改$a_x$的时候先将$a_x$的出现次数在树上剪掉$b_x$,再在$y$上面加上;修改$b_x$的时候直接加上变化量$y-b_x$。由于我们是要取前$x$大的$a_i$之和,在询问的时候有限考虑右儿子,然后在是当前......
  • AT_abc335_f [ABC335F] Hop Sugoroku 题解
    比E简单。分析考虑暴力DP。定义状态函数$f_i$表示最后一个黑点为$i$时的方案数,有:$f_i=\sum\limits_{j=1}^{i-1}f_j[(i-j)\bmodval_j=0]$。不难发现在使用刷表法的时候,转移代码:for(reintj=1;i+val[i]*j<=n;++j)f[i+val[i]*j]=(f[i+val[i]*j]+f[i])%p;这玩意复杂......
  • AT_abc190_e [ABC190E] Magical Ornament 题解
    分析考虑状压。定义状态函数$f_{i,j}$表示在得到$C$出现过的状态为$i$且排列末尾为$j$时的最小代价。则有转移方程:$f_{i,j}=\min{f_{i',k}+dis_{k,j}}$,保证$i'$表示集合属于$i$。$dis_{i,j}$跑最短路就行了,通过枚举$C_i$为起点可以做到$O(kn\logn)$的复杂度求......
  • CF1800F Dasha and Nightmares 题解
    分析考虑枚举。注意到第二个条件是必须要有$25$个字符在里面出现过,故考虑枚举唯一没出现过的字符$k$,然后再枚举$s_i$。令$cnt_{i,j}$表示$s_i$中字符$c$出现的奇偶性。如果有字符$c\nek\landcnt_{i,c}=0$,则在$s_j$中必有$cnt_{j,c}=1$;反之同理。枚举字符$c......
  • P5655 基础数论函数练习题 题解
    分析考虑莫队。令$S=\operatorname{lcm}(a_l,a_{l+1},a_{l+2},\dots,a_{r-1})$。则对于新加进来的$a_r$,有:$$\operatorname{lcm}(a_l,a_{l+1},a_{l+2},\dots,a_{r-1},a_r)\=\operatorname{lcm}(S,a_r)\=\frac{S\timesa_r}{\gcd(S,a_r)}$$很容易发现,$S$在不取模的情况下会......
  • CF163A Substring and Subsequence 题解
    分析考虑DP。定义状态函数$f_{i,j}$表示在$s[1\dotsi]$中选一个子串$a$,在$t[1\dotsj]$中选一个子序列$b$,且$s_i,t_j$必选时$a=b$的方案数。则有两种情况:$s_i\net_j$。此时$a$和$b$是不可能相同的了,所以$f_{i,j}=0$。$s_i=t_j$。在只选$s_i,t_j$时......
  • CF101B Buses 题解
    分析考虑DP。由于$n$很大,而$m$可以接受,考虑根据公交车定义状态函数。很容易想到一种状态函数:$f_i$表示做第$i$辆公交车到$t_i$的方案数。根据题意,就有转移方程:$f_i=\sumf_j[s_i\let_j\let_i-1]+k$,$k$在$s_i=0$时为$1$,其余为$0$。然后这题就会了。求和部分......
  • AT_abc263_f [ABC263F] Tournament 题解
    分析一眼DP。定义状态函数$f_{i,j}$表示在第$i$此比赛中,获胜者为$j$时的最大奖学金。把比赛过程看成一棵倒着的满二叉树,就能发现:第$i$场比赛只会是其左儿子为根的子树中叶子节点的某一个与其右儿子为根的子树中叶子节点的某一个进行比赛。然后就可以得到转移方程:$f_{i,......
  • P10149 [Ynoi1999] XM66F 题解
    分析考虑莫队。对于$a_i=k(l\lei\ler)$的下标集合$S_k$,当其加入一个新的下标$x$时,这个新下标对答案的贡献分两种情况。第一种,$x$最小。相邻从下标的间隔中产生的贡献是$\sum(|S_k|-i+1)\times(ans_{S_{k,i+1}}-ans_{S_{k,i}})$。画个图可以理解一下:第二中,$x$最......