HDU5828-Rikka with Sequence

本文介绍了一道涉及数学运算的编程题目,包括区间加法、开方和求和操作。通过实现一种特殊的数据结构来高效处理这些操作,并提供了解决方案的源代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Rikka with Sequence

                                                                 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
                                                                                         Total Submission(s): 3161    Accepted Submission(s): 575


Problem Description
As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:

Yuta has an array A with n numbers. Then he makes m operations on it. 

There are three type of operations:

1 l r x : For each i in [l,r], change A[i] to A[i]+x
2 l r : For each i in [l,r], change A[i] to  A[i]
3 l r : Yuta wants Rikka to sum up A[i] for all i in [l,r]

It is too difficult for Rikka. Can you help her?
 

Input
The first line contains a number t(1<=t<=100), the number of the testcases. And there are no more than 5 testcases with n>1000.

For each testcase, the first line contains two numbers n,m(1<=n,m<=100000). The second line contains n numbers A[1]~A[n]. Then m lines follow, each line describe an operation.

It is guaranteed that 1<=A[i],x<=100000.
 

Output
For each operation of type 3, print a lines contains one number -- the answer of the query.
 

Sample Input
  
1 5 5 1 2 3 4 5 1 3 5 2 2 1 4 3 2 4 2 3 5 3 1 5
 

Sample Output
  
5 6
 

Author
学军中学
 

Source
 

Recommend
wange2014
 


题意: 区间有三种操作:区间加,区间开根和区间求和

解题思路:一开始我和大部分人一样是去判断一个区间里的数是不是全都一样,一样的话就可以区间更新,速度会比较快。不过据说后来数据加强了,数据中出现了sqrt以后仍旧不相等的情况,比如x和x+1,每次加上x^2+x,之后再开方,会保持原来的序列不变。解决这种情况的办法就是再多考虑极差为1的情况,区间值之间的差一定会趋向于0或1,而不会是更大的数。所以在原来的情况下加上判断极差为1的情况(判断区间最大值和最小值的差值即可),此时的开方操作相当于区间减操作,因为开方前相差1,开方后仍旧是相差1


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <map>
#include <cmath>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <functional>

using namespace std;

#define LL long long
const int INF = 0x3f3f3f3f;

int n, m, p, x, y;
LL sum[100009 << 2], mi[100009 << 2], ma[100009 << 2], lazy[100009 << 2], z;

void Merge(int k)
{
	mi[k] = min(mi[k << 1], mi[k << 1 | 1]);
	ma[k] = max(ma[k << 1], ma[k << 1 | 1]);
	sum[k] = sum[k << 1] + sum[k << 1 | 1];
}

void build(int k, int l, int r)
{
	lazy[k] = 0;
	if (l == r) { scanf("%lld", &sum[k]); ma[k] = mi[k] = sum[k]; return; }
	int mid = l + r >> 1;
	build(k << 1, l, mid), build(k << 1 | 1, mid + 1, r);
	Merge(k);
}

void Push(int k, int l, int r)
{
	int mid = (l + r) >> 1;
	if (lazy[k])
	{
		lazy[k << 1] += lazy[k]; mi[k << 1] += lazy[k]; ma[k << 1] += lazy[k];
		sum[k << 1] += lazy[k] * (mid - l + 1);
		lazy[k << 1 | 1] += lazy[k];    mi[k << 1 | 1] += lazy[k];    ma[k << 1 | 1] += lazy[k];
		sum[k << 1 | 1] += lazy[k] * (r - mid);
	}
	if (mi[k] == ma[k])
	{
		mi[k << 1] = ma[k << 1] = mi[k << 1 | 1] = ma[k << 1 | 1] = mi[k];
		sum[k << 1] = mi[k] * (mid - l + 1);
		sum[k << 1 | 1] = ma[k] * (r - mid);
	}
	lazy[k] = 0;
}

void update(int k, int l, int r, int ll, int rr, LL val)
{
	if (ll <= l && r <= rr)
	{
		lazy[k] += val; mi[k] += val; ma[k] += val;
		sum[k] += val * (r - l + 1); return;
	}
	int mid = l + r >> 1;
	if (lazy[k] || mi[k] == ma[k]) Push(k, l, r);
	if (ll <= mid) update(k << 1, l, mid, ll, rr, val);
	if (rr > mid) update(k << 1 | 1, mid + 1, r, ll, rr, val);
	Merge(k);
}

void update(int k, int l, int r, int ll, int rr)
{
	if (ll <= l && r <= rr)
	{
		if ((LL)sqrt(mi[k]) == (LL)sqrt(ma[k]))
		{
			mi[k] = ma[k] = sqrt(ma[k]);
			sum[k] = mi[k] * (r - l + 1);
		}
		else if (mi[k] + 1 == ma[k])
		{
			LL kk = ma[k] - 1LL * sqrt(ma[k]);
			lazy[k] -= kk, ma[k] -= kk, mi[k] -= kk, sum[k] -= (r - l + 1)*kk;
		}
		else
		{
			int mid = l + r >> 1;
			if (lazy[k] || mi[k] == ma[k]) Push(k, l, r);
			if (ll <= mid) update(k << 1, l, mid, ll, rr);
			if (rr > mid) update(k << 1 | 1, mid + 1, r, ll, rr);
			Merge(k);
		}
		return;
	}
	int mid = l + r >> 1;
	if (lazy[k] || mi[k] == ma[k]) Push(k, l, r);
	if (ll <= mid) update(k << 1, l, mid, ll, rr);
	if (rr > mid) update(k << 1 | 1, mid + 1, r, ll, rr);
	Merge(k);
}

LL query(int k, int l, int r, int ll, int rr)
{
	if (ll <= l && r <= rr) return sum[k];
	int mid = l + r >> 1;
	if (lazy[k] || mi[k] == ma[k]) Push(k, l, r);
	LL ans = 0;
	if (ll <= mid) ans += query(k << 1, l, mid, ll, rr);
	if (rr > mid) ans += query(k << 1 | 1, mid + 1, r, ll, rr);
	return ans;
}

int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d", &n, &m);
		build(1, 1, n);
		while (m--)
		{
			scanf("%d%d%d", &p, &x, &y);
			if (p == 1)
			{
				scanf("%lld", &z);
				update(1, 1, n, x, y, z);
			}
			else
			{
				if (p == 2) update(1, 1, n, x, y);
				else printf("%lld\n", query(1, 1, n, x, y));
			}
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值