梦迹(树状数组好题)

C-梦迹_牛客练习赛108 (nowcoder.com)

题目描述
云浅现在手上没有数了,不过她变出来了n个非负整数a1, ag, … , @n。她又给了你一个非负整数W。现在有q次修改,每次给出p, c,你需要令ap <一Z。
在每次修改后,你需要输出满足ai+ aj≤W,i≤j的数对(i,j)的个数。
输入描述:
第一行三个正整数n, q,W。
第二行n个正整数a1, a2,…- ,an表示云浅的n个数。接下来q行,每行两个非负整数 p, c,表示一次修改。
对于100%的数据,1≤n,q≤3x105,0 ≤a, 2 ≤w<3x 10°,1≤p ≤n。
输出描述:
输出q行,表示每次修改后满足ai+ aj≤W,i≤j 的数对(i,j)的个数。
示例1
示例1

输入

复制

4 3 6
1 0 4 6 
2 2
4 4
1 2

输出

复制

5
7
7


说明
第一次操作后,a= (1,2,4,6),符合条件的(i,j))有:(1,1),(1,2),(1,3),(2,2),(2,3)。
第二次操作后,a=(1,2,4,4),符合条件的(i,j)有:(1,1),(1.2),(1.3),(1,4),(2,2),(2,3),(2,4)。第三次操作后,a= (2,2,4,4),符合条件的(i,j)有:(1,1),(1,2),(1,3),(1,4),(2,2),(2,3),(2,4)。
备注:
对于100%的数据,1≤n,q≤3×105,0≤ai, a ≤ W<3 x105,1≤p≤n。

题解:

本题之所以是好题,是要明白数组数组查询和修改的含义

修改:位置i,加上一个值

查询:前i个位置相加和

由于ai <= 300000,我们可以用树状数组记录位置ai出现的次数,为啥这样记录呢?
查询时就可以查询前缀和(w - a[i])就是答案,位置小于等于w - a[i]的个数

由于树状数组的下标不能从0开始,而ai可以为0,会导致数组数组下标从0开始,所以树状数组整体下标+1

#include 
#include 
#include 
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair PII;
#define int long long
int tre[300050];
int n,q,W;
int lowbit(int x)
{
	return x & -x;
}
void updata(int x,int w)
{
	for(x ++ ;x <= W + 1;x += lowbit(x))
	tre[x] += w;
}
int sum(int x)
{
	int ans = 0;
	for(x++;x;x -= lowbit(x))
	{
		ans += tre[x];
	}
	return ans;
}
int a[300050];
void solve()
{
	cin >> n >> q >> W;
	int ans = 0;
	for(int i = 1;i <= n;i++)
	{
		cin >> a[i];
		updata(a[i],1);
		ans += sum(W - a[i]);
	}
	while(q--)
	{
		int x,y;
		cin >> x>> y;
		ans -= sum(W - a[x]);
		updata(a[x],-1);
		a[x] = y;
		updata(a[x],1);
		ans += sum(W - a[x]);
		cout << ans <<"\n";
	}
}


signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
	int t = 1;
//	cin >> t;
	while(t--)
	{
		solve(); 
	}
}

你可能感兴趣的:(算法,c++,开发语言)