2020ICPC小米邀请赛C Data Structure Problem 数据结构

C Data Structure Problem

链接:https://ac.nowcoder.com/acm/contest/7502/C
题目来源:牛客网

题目描述

Bobo has two sequences a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an​ and b 1 , b 2 , … , b n b_1, b_2, \ldots, b_n b1,b2,,bn. He would like to perform the following operations:

  • 1  x   y \text{1 }x\ y x y, change the value of a x a_x axto y.
  • 2  x   y \text{2 }x\ y x y, change the value of b x b_x bxto y.
  • 3  x \text{3 }x x, find the value of c x c_x cx, where c 0 = 0 c_0=0 c0=0, c i = max ⁡ ( c i − 1 + b i , a i )  for  1 ≤ i ≤ x c_i=\max(c_{i-1}+b_i,a_i) \text{ for } 1 \le i \le x ci=max(ci1+bi,ai) for 1ix

输入描述:

The input consists of several test cases terminated by end-of-file. For each test case:
The first line contains two integers n and m , which are the length of the two sequences and the number of operations. The second line contains n integers a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an . The third line contains n integers b 1 , b 2 , … , b n b_1, b_2, \ldots, b_n b1,b2,,bn. Each of the last m lines contains a query.

  • 1 ≤ n , m ≤ 2 × 1 0 5 1 \leq n, m \leq 2 \times 10^5 1n,m2×105
  • − 1 0 9 ≤ a i , b i , y ≤ 1 0 9 -10^9 \leq a_i, b_i, y \leq 10^9 109ai,bi,y109
  • 1 ≤ x ≤ n 1 \leq x \leq n 1xn
  • The sum of n and the sum of m do not exceed 2 × 1 0 6 2 \times 10^6 2×106.

输出描述:

For each query of \text{3 }x3 x, output an integer denoting the value of c x c_x cx.

示例

4 9
1 2 3 3
-1 2 3 3
3 1
3 2
3 3
3 4
2 2 -4
3 1
3 2
3 3
3 4

输出

1
3
6
9
1
2
5
8

思路

很容易想到对于每个3 x询问,你将输出一个 a i + b i + 1 + … + b t a_i+b_{i+1}+\ldots+b_{t} ai+bi+1++bt,当然,如果 i = t i=t i=t也是有可能的。所以首先想到的是,用前缀和维护 b i b_i bi(于是,在比赛的时候我卡住了)。那么, a n s x = m a x i x ( a i + S x − S i ) = S x + m a x i x ( a i − S i ) ans_x=max^x_i(a_i+S_x-S_i)=Sx+max^x_i(a_i-S_i) ansx=maxix(ai+SxSi)=Sx+maxix(aiSi)。对于这个公式,只要用线段树维护 a i − S i a_i-S_i aiSi即可。
对于操作1,单点修改a[x]即可;
对于操作2,区间修改sumb[x]-sumb[n];
对于询问3,区间1~x取出 m a x ( a i − S i ) max(a_i-S_i) max(aiSi)在加上 S x S_x Sx即可。但注意,我们的 S x S_x Sx是没有维护过的,因此我们需要利用维护好的线段树结果算出 S x = a [ x ] − t r x S_x=a[x]-tr_x Sx=a[x]trx

ac代码

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<iomanip>

using namespace std;
#define LL long long
#define MOD 1000000007
#define MAXN 10000007
const int INF = 0x3f3f3f3f;
const int N = 200010;
LL read()
{
	LL w = 1, x = 0;
	char ch = 0;
	while (ch < '0' || ch>'9')
	{
		if (ch == '-')
			w = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
	{
		x = x * 10 + (ch - '0');
		ch = getchar();
	}
	return w * x;
}

LL sumb[N], a[N], b[N];
LL la[N << 2], tr[N << 2];
int n, m;

void build(int l, int r, int n)
{
	la[n] = 0;
	if (l == r)
	{
		tr[n] = a[l] - sumb[l];
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, n << 1);
	build(mid + 1, r, n << 1 | 1);
	tr[n] = max(tr[n << 1], tr[n << 1 | 1]);
}
void pushdown(int n)
{
	if (la[n] == 0)
	{
		return ;
	}
	tr[n << 1] += la[n];
	tr[n << 1 | 1] += la[n];
	la[n << 1] += la[n];
	la[n << 1 | 1] += la[n];
	la[n] = 0;
	return;
}

void add(int al, int ar, LL x, int l, int r, int n)
{
	if (al <= l && r <= ar)
	{
		tr[n] += x;
		la[n] += x;
		return;
	}
	pushdown(n);
	int mid = (l + r) >> 1;
	if (al <= mid)
	{
		add(al, ar, x, l, mid, n << 1);
	}
	if (ar > mid)
	{
		add(al, ar, x, mid + 1, r, n << 1 | 1);
	}
	tr[n] = max(tr[n << 1], tr[n << 1 | 1]);
}

LL query(int al, int ar, int l, int r, int n)
{
	if (al <= l && r <= ar)
	{
		return tr[n];
	}
	pushdown(n);
	int mid = (l + r) >> 1;
	int fl = 0;
	LL ans = 0;
	if (al <= mid)
	{
		fl = 1;
		ans = query(al, ar, l, mid, n << 1);
	}
	if (ar > mid)
	{
		if (fl)
		{
			ans = max(ans, query(al, ar, mid + 1, r, n << 1 | 1));
		}
		else
		{
			ans = query(al, ar, mid + 1, r, n << 1 | 1);
		}
	}
	tr[n] = max(tr[n << 1], tr[n << 1 | 1]);
	return ans;
}

int main()
{
	while (cin >> n >> m)
	{
		for (int i = 1; i <= n; ++i)
		{
			scanf("%lld", &a[i]);
		}
		for (int i = 1; i <= n; ++i)
		{
			scanf("%lld", &b[i]);
			sumb[i] = sumb[i - 1] + b[i];
		}
		build(1, n, 1);
		for (int i = 1; i <= m; ++i)
		{
			int qqq, x;
			LL y;
			scanf("%d", &qqq);
			if (qqq == 1)
			{
				scanf("%d %lld", &x, &y);
				add(x, x, y - a[x], 1, n, 1);
				a[x] = y;
			}
			else if (qqq == 2)
			{
				scanf("%d %lld", &x, &y);
				add(x, n, -(y - b[x]), 1, n, 1);
				b[x] = y;
			}
			else if (qqq == 3)
			{
				scanf("%d", &x);
				LL res = max(0LL, query(1, x, 1, n, 1));
				res += (a[x] - query(x, x, 1, n, 1));
				printf("%lld\n", res);
			}
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值