给定一个由N个整数组成的数组arr [] ,一个整数X和一个由以下两种类型的查询组成的2D数组query [] []:
- (L,R,0):将[L,R]范围内的所有数组元素增加一个值X。
- (L,R,1):在[L,R]范围内将所有数组元素设置为X。
- (L,R,2):打印 元素在[L,R]范围内的平方和。
例子:
Input: arr[] = {1, 2, 3, 4}, X = 2, queries[][] = {{1, 3, 0}, {1, 2, 2}, {3, 3, 1}, {2, 3, 2}}
Output: 41 29
Explanation:
Query 1: Increment all array elements present in the range of indices [1, 3] by X ( = 2). The array modifies to {1, 4, 5, 6, 5}.
Query 2: Sum of squares of array elements present in the range of indices [1, 2] = 4*4 + 5*5 = 41.
Query 3: Updating all array elements to X(= 2) in the range of indices [3, 3]. The array modifies to {1, 4, 5, 2, 5}.
Query 4: Sum of squares of array elements in the range of indices [2, 3] = 5 * 5 + 2 * 2 = 29.
Input: arr[] = {2, 4, 1, 5}, X = 3, queries[][] = {{1, 3, 1}, {1, 3, 0}, {2, 3, 0}}
Output: 27 18
天真的方法:最简单的方法是在每个查询的给定范围内遍历给定数组,并在给定数组上执行相应的查询并相应地打印结果。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Function to find the sum of squares
// of elements present in the range of
// indices [l, r] in the array v[]
long long rangesum(vector& v,
int l, int r)
{
long long sum = 0;
// Iterate over range l to r
for (int i = l; i <= r; i++) {
// Add square of current
// element to the sum
sum += v[i] * v[i];
}
// Return the sum
return sum;
}
// Function to perform given queries
void rangeQuery(vector& v, int l,
int r, int update,
int type)
{
// For type 1 update
if (type == 1) {
// Iterate over range l to r
// and update the array elements
for (int i = l; i <= r; i++) {
v[i] = update;
}
}
// For type 0 update
else {
// Iterate over range l to r
// and update the elements
for (int i = l; i <= r; i++) {
v[i] += update;
}
}
}
// Function to print the result
// for the given queries
void printAnswer(vector > query,
vector a, int X)
{
// Iterate over the query[]
for (int i = 0;
i < query.size(); i++) {
int l = query[i][0];
int r = query[i][1];
if (query[i][2] == 0) {
// Add by X modified array
// will be considered for
// the operation
rangeQuery(a, l, r, X, 0);
}
else if (query[i][2] == 1) {
// Substitute by X
rangeQuery(a, l, r, X, 1);
}
else {
// Print the range sum
cout << rangesum(a, l, r)
<< " ";
}
}
}
// Driver Code
int main()
{
vector arr = { 1, 2, 3, 4, 5 };
int X = 2;
vector > query = {
{ 1, 3, 0 }, { 1, 2, 2 },
{ 3, 4, 1 }, { 2, 3, 2 }
};
printAnswer(query, arr, X);
return 0;
}
C++
// C++ program of the above approach
#include
using namespace std;
// Used to create Segment Tree
vector seg(400000, 0),
dseg(400000, 0),
a(100000);
// Stores the segment sum
vector segSum(400000, 0);
// Building the segment tree
void build(int ind, int low, int high)
{
// If low is the same as high
if (low == high) {
// Update the segment node
seg[ind] = a[low] * a[low];
segSum[ind] = a[low];
return;
}
// Find the mid
int mid = (low + high) / 2;
// Recursively call for
// the two halves of the tree
build(2 * ind + 1, low, mid);
build(2 * ind + 2, mid + 1, high);
// Update the segment node
seg[ind] = seg[2 * ind + 1]
+ seg[2 * ind + 2];
// Update the segment sum
segSum[ind] = segSum[2 * ind + 1]
+ segSum[2 * ind + 2];
}
// Function to find the sum of squares
// of array elements in the given range
long long rangesum(int ind, int low,
int high, int l,
int r)
{
// Pending updates if any
if (dseg[ind] != 0) {
// Update the square
// over segment node
seg[ind] += (high - low + 1)
* dseg[ind]
* dseg[ind]
+ (2 * dseg[ind]
* segSum[ind]);
// Update the square over
// the segment sum
segSum[ind] += (high - low + 1)
* dseg[ind];
// If low and high are different
if (low != high) {
dseg[2 * ind + 1] += dseg[ind];
dseg[2 * ind + 2] += dseg[ind];
}
dseg[ind] = 0;
}
// Out of bounds
if (r < low || l > high
|| low > high) {
return 0;
}
// Completely within the range
if (l <= low && r >= high) {
return seg[ind];
}
// Partially overlapping
int mid = (low + high) / 2;
// Return the range sum
return rangesum(2 * ind + 1,
low, mid, l, r)
+ rangesum(2 * ind + 2,
mid + 1, high,
l, r);
}
// Function to perform the given queries
void rangeQuery(int ind, int low,
int high, int l, int r,
int update, int type)
{
// Pending updates if any
if (dseg[ind] != 0) {
// Update the segment node
seg[ind]
+= (high - low + 1)
* dseg[ind] * dseg[ind];
// Update the segment sum
segSum[ind] += (high - low + 1)
* dseg[ind];
if (low != high) {
dseg[2 * ind + 1] += dseg[ind];
dseg[2 * ind + 2] += dseg[ind];
}
dseg[ind] = 0;
}
// Out of bounds
if (r < low || l > high
|| low > high) {
return;
}
// Completely within the range
if (l <= low && r >= high) {
// Substitute with X
if (type == 1) {
// Updating the current
// index for sum of square
seg[ind] = (high - low + 1)
* update * update;
// Updating the current
// index for sum
segSum[ind] = (high - low + 1)
* update;
}
else {
// Add X updating the current
// index for sum of square
seg[ind] += (high - low + 1)
* update * update
+ 2 * update
* segSum[ind];
// Updating the current
// index for sum
segSum[ind] += (high - low + 1)
* update;
}
// Lazy update
if (low != high) {
dseg[2 * ind + 1] += update;
dseg[2 * ind + 2] += update;
}
return;
}
// Partially overlapping
int mid = (low + high) / 2;
rangeQuery(2 * ind + 1, low,
mid, l, r, update,
type);
rangeQuery(2 * ind + 2, mid + 1,
high, l, r, update,
type);
// Updating sum of squares
// and sum while bactracking
seg[ind] = seg[2 * ind + 1]
+ seg[2 * ind + 2];
segSum[ind] = segSum[2 * ind + 1]
+ segSum[2 * ind + 2];
}
// Function to print the answer
// for the given queries
void printAnswer(
vector > query,
int N, int X)
{
// Build Segment tree
build(0, 0, N - 1);
// Traverse queries
for (int i = 0;
i < query.size(); i++) {
int l = query[i][0];
int r = query[i][1];
if (query[i][2] == 0) {
// Add by X, modified
// array will be considered
// for operation
rangeQuery(0, 0, N - 1, l, r, X, 0);
}
else if (query[i][2] == 1) {
// Substitute by X modified
// array will be considered
// for operation
rangeQuery(0, 0, N - 1,
l, r, X, 1);
}
else {
cout << rangesum(0, 0, N - 1,
l, r)
<< " ";
}
}
}
// Driver Code
int main()
{
a = { 1, 2, 3, 4 };
int X = 2;
int N = (int)a.size();
// Given queries
vector > query = {
{ 1, 3, 0 }, { 1, 2, 2 },
{ 3, 3, 1 }, { 2, 3, 2 }
};
printAnswer(query, N, X);
return 0;
}
41 29
时间复杂度: O(Q * N)
辅助空间: O(N + Q)
高效方法:可以使用段树来优化上述方法。请按照以下步骤解决问题:
- 初始化两个数组seg []和segSum [] ,其中seg []存储平方和,而segSum []存储范围[L,R]中的元素之和。
- 由于以下原因,存储数组元素的总和:
- 考虑以下示例, arr [] = {a,b,c,d,e},范围= {1,3},X =K。
- 在给定范围[1,3]中将每个元素增加K时,该值变为:
(b + K)2 + (c + K)2 + (d + K)2 = (b2 + c2 + d2) + 3 * K2 + 2 * K * (b + c + d),
which can be generalized as the sum of squares + (high – low + 1) * X * X + sum of elements.
- 在此范围内将X = K替换为(K) 2 +(K) 2 +(K) 2 = 3 * K 2 ,可以将其推广为:(高–低+ 1)* X *X 。
- 使用上述公式更新范围[L,R]内的数组元素的平方和,并为每个类型2的查询相应地打印范围和。
下面是上述方法的实现:
C++
// C++ program of the above approach
#include
using namespace std;
// Used to create Segment Tree
vector seg(400000, 0),
dseg(400000, 0),
a(100000);
// Stores the segment sum
vector segSum(400000, 0);
// Building the segment tree
void build(int ind, int low, int high)
{
// If low is the same as high
if (low == high) {
// Update the segment node
seg[ind] = a[low] * a[low];
segSum[ind] = a[low];
return;
}
// Find the mid
int mid = (low + high) / 2;
// Recursively call for
// the two halves of the tree
build(2 * ind + 1, low, mid);
build(2 * ind + 2, mid + 1, high);
// Update the segment node
seg[ind] = seg[2 * ind + 1]
+ seg[2 * ind + 2];
// Update the segment sum
segSum[ind] = segSum[2 * ind + 1]
+ segSum[2 * ind + 2];
}
// Function to find the sum of squares
// of array elements in the given range
long long rangesum(int ind, int low,
int high, int l,
int r)
{
// Pending updates if any
if (dseg[ind] != 0) {
// Update the square
// over segment node
seg[ind] += (high - low + 1)
* dseg[ind]
* dseg[ind]
+ (2 * dseg[ind]
* segSum[ind]);
// Update the square over
// the segment sum
segSum[ind] += (high - low + 1)
* dseg[ind];
// If low and high are different
if (low != high) {
dseg[2 * ind + 1] += dseg[ind];
dseg[2 * ind + 2] += dseg[ind];
}
dseg[ind] = 0;
}
// Out of bounds
if (r < low || l > high
|| low > high) {
return 0;
}
// Completely within the range
if (l <= low && r >= high) {
return seg[ind];
}
// Partially overlapping
int mid = (low + high) / 2;
// Return the range sum
return rangesum(2 * ind + 1,
low, mid, l, r)
+ rangesum(2 * ind + 2,
mid + 1, high,
l, r);
}
// Function to perform the given queries
void rangeQuery(int ind, int low,
int high, int l, int r,
int update, int type)
{
// Pending updates if any
if (dseg[ind] != 0) {
// Update the segment node
seg[ind]
+= (high - low + 1)
* dseg[ind] * dseg[ind];
// Update the segment sum
segSum[ind] += (high - low + 1)
* dseg[ind];
if (low != high) {
dseg[2 * ind + 1] += dseg[ind];
dseg[2 * ind + 2] += dseg[ind];
}
dseg[ind] = 0;
}
// Out of bounds
if (r < low || l > high
|| low > high) {
return;
}
// Completely within the range
if (l <= low && r >= high) {
// Substitute with X
if (type == 1) {
// Updating the current
// index for sum of square
seg[ind] = (high - low + 1)
* update * update;
// Updating the current
// index for sum
segSum[ind] = (high - low + 1)
* update;
}
else {
// Add X updating the current
// index for sum of square
seg[ind] += (high - low + 1)
* update * update
+ 2 * update
* segSum[ind];
// Updating the current
// index for sum
segSum[ind] += (high - low + 1)
* update;
}
// Lazy update
if (low != high) {
dseg[2 * ind + 1] += update;
dseg[2 * ind + 2] += update;
}
return;
}
// Partially overlapping
int mid = (low + high) / 2;
rangeQuery(2 * ind + 1, low,
mid, l, r, update,
type);
rangeQuery(2 * ind + 2, mid + 1,
high, l, r, update,
type);
// Updating sum of squares
// and sum while bactracking
seg[ind] = seg[2 * ind + 1]
+ seg[2 * ind + 2];
segSum[ind] = segSum[2 * ind + 1]
+ segSum[2 * ind + 2];
}
// Function to print the answer
// for the given queries
void printAnswer(
vector > query,
int N, int X)
{
// Build Segment tree
build(0, 0, N - 1);
// Traverse queries
for (int i = 0;
i < query.size(); i++) {
int l = query[i][0];
int r = query[i][1];
if (query[i][2] == 0) {
// Add by X, modified
// array will be considered
// for operation
rangeQuery(0, 0, N - 1, l, r, X, 0);
}
else if (query[i][2] == 1) {
// Substitute by X modified
// array will be considered
// for operation
rangeQuery(0, 0, N - 1,
l, r, X, 1);
}
else {
cout << rangesum(0, 0, N - 1,
l, r)
<< " ";
}
}
}
// Driver Code
int main()
{
a = { 1, 2, 3, 4 };
int X = 2;
int N = (int)a.size();
// Given queries
vector > query = {
{ 1, 3, 0 }, { 1, 2, 2 },
{ 3, 3, 1 }, { 2, 3, 2 }
};
printAnswer(query, N, X);
return 0;
}
41 29
时间复杂度: O(Q * log N)
辅助空间: O(N)