【线段树】P5026 Lycanthropy|普及+

本文涉及知识点

C++线段树

P5026 Lycanthropy

题目背景

小正方形亲眼看见了自己昔日的朋友被卷进了黑暗的深渊,然而它无力阻止……

现在它的朋友已经向它发起了攻击,因此小正方形不得不抵抗。

题目描述

我们把山顶上的湖泊看作一条长度为 m m m 的直线,一开始水深都在水平线上,我们视作此时的水深为 ‘0’

接下来,在一瞬间,小正方形的"朋友"们跳起并扎入水中,导致在入水点的水降低而远离入水点的水升高,注意两个 “朋友” 可能在同一地点入水。

小正方形的每个朋友有一个体积数值 v v v,当体积为 v v v 的一个朋友跳入水中,我们设入水点为 i i i,将会导致 i − v + 1 i - v + 1 iv+1 i i i 的水位依次降低 1 , 2 , ⋯   , v 1,2,\cdots,v 1,2,,v

同样地,第 i i i i + v − 1 i + v - 1 i+v1 的水位会依次降低 v , v − 1 , ⋯   , 1 v,v - 1,\cdots,1 v,v1,,1.

相对应地, i − v i - v iv 的水位不变, i − v − 1 i - v - 1 iv1 i − 2 ∗ v i - 2 * v i2v 水位依次增加 1 , 2 , ⋯   , v 1,2,\cdots,v 1,2,,v i − 2 ∗ v i - 2 * v i2v i − 3 ∗ v + 1 i - 3 * v + 1 i3v+1 水位依次增加 v , v − 1 , ⋯   , 1 v,v - 1,\cdots,1 v,v1,,1

同样, i + v i + v i+v 水位不变, i + v + 1 i + v + 1 i+v+1 i + 2 ∗ v i + 2 * v i+2v 水位增加 1 , 2 , ⋯   , v 1,2,\cdots,v 1,2,,v i + 2 ∗ v i + 2 * v i+2v i + 3 ∗ v − 1 i + 3 * v - 1 i+3v1 水位依次增加 v , v − 1 , ⋯   , 1 v,v - 1,\cdots,1 v,v1,,1

现在小正方形想要穿过这个湖,他想要知道在这 n n n 个"朋友"跳入水中后湖上每个节点的水位,你能帮帮它吗?

输入格式

第一行为两个整数 n n n, m m m,表示"朋友"的数目与湖泊的宽度。

接下来 n n n 行,一行两个整数 v , x v,x v,x,表示第 i + 1 i + 1 i+1 个朋友的体积与入水点。

输出格式

一行 m m m 个整数,第 i i i 个整数表示 i i i 号位的水深。

输入输出样例 #1

输入 #1

1 10
1 5

输出 #1

0 0 1 0 -1 0 1 0 0 0

输入输出样例 #2

输入 #2

2 10
2 6
3 1

输出 #2

-2 0 0 0 0 0 2 2 2 2

说明/提示

对于 30 % 30\% 30% 的数据, n < = 50 , m < = 500 n <= 50,m <= 500 n<=50,m<=500

对于 70 % 70\% 70% 的数据, n < = 1 0 5 , m < = 1 0 5 n <= 10^5,m <= 10^5 n<=105,m<=105

对于 100 % 100\% 100% 的数据, n < = 1 0 6 , m < = 1 0 6 , 1 < = v < = 10000 , 1 < = x < = m n <= 10^6,m <= 10^6,1 <= v <= 10000,1 <= x <= m n<=106,m<=106,1<=v<=10000,1<=x<=m

线段树 P5026 Lycanthropy

TSave:long long ,记录水深。
TRecord :long long ,long long,简称{i1,i2}
由于只单点查询,故可以只处理叶子节点。不更新父节点。查询直接等于。
更新:save += iiSaveLeft+i2
更新缓存:i1旧 += i1新,i2旧 += i2新。
[left,r]分别更新k ,k+d,k+2dKaTeX parse error: Undefined control sequence: \cvdots at position 1: \̲c̲v̲d̲o̲t̲s̲
lineTree.Update(left,r,{d,k-left
d})
[i,i+2v] 增加-v到v,步长1。
[i+2v+1,i+3v]增加v-1到0,步长-1。
[i-2v,i-1] 增加v到-(v-1),不长-1。
[i-3v,i-(2v+1)] 增加0到v-1,步长1。
封装Update(left,r,leftv,d)函数,d是步长,逻辑如下:
如果[left,r]和[0,m]没有公共部分,return。
r = min(r,m)
如果left < 0
val += (0 - left)*d
left = 0
时间复杂度:O(nlogm),n=1e5时,只需要0.2s;n = 1e6,时超时。

代码

#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>

#include <bitset>
using namespace std;

template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {
	in >> pr.first >> pr.second;
	return in;
}

template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t);
	return in;
}

template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
	return in;
}

template<class T = int>
vector<T> Read() {
	int n;
	scanf("%d", &n);
	vector<T> ret(n);
	for (int i = 0; i < n; i++) {
		cin >> ret[i];
	}
	return ret;
}

template<class T = int>
vector<T> Read(int n) {
	vector<T> ret(n);
	for (int i = 0; i < n; i++) {
		cin >> ret[i];
	}
	return ret;
}

template<int N = 1'000'000>
class COutBuff
{
public:
	COutBuff() {
		m_p = puffer;
	}
	template<class T>
	void write(T x) {
		int num[28], sp = 0;
		if (x < 0)
			*m_p++ = '-', x = -x;

		if (!x)
			*m_p++ = 48;

		while (x)
			num[++sp] = x % 10, x /= 10;

		while (sp)
			*m_p++ = num[sp--] + 48;
		AuotToFile();
	}
	inline void write(char ch)
	{
		*m_p++ = ch;
		AuotToFile();
	}
	inline void ToFile() {
		fwrite(puffer, 1, m_p - puffer, stdout);
		m_p = puffer;
	}	
	~COutBuff() {
		ToFile();
	}
private:
	inline void AuotToFile() {
		if (m_p - puffer > N - 100) {
			ToFile();
		}
	}
	char  puffer[N], * m_p;
};

template<int N = 12 * 1'000'000>
class CInBuff
{
public:
	inline CInBuff() {
		fread(buffer, 1, N, stdin);
	}
	inline int Read() {
		int x(0), f(0);
		while (!isdigit(*S))
			f |= (*S++ == '-');
		while (isdigit(*S))
			x = (x << 1) + (x << 3) + (*S++ ^ 48);
		return f ? -x : x;
	}
private:
	char buffer[N], * S = buffer;
};

template<class TSave, class TRecord >
class CRangUpdateLineTree
{
protected:
	virtual void OnQuery(TSave& ans, const TSave& save, const int& iSaveLeft, const int& iSaveRight) = 0;
	virtual void OnUpdate(TSave& save, const int& iSaveLeft, const int& iSaveRight, const TRecord& update) = 0;
	virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r, const int& iSaveLeft, const int& iSaveRight) = 0;
	virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) = 0;
};

template<class TSave, class TRecord >
class CVectorRangeUpdateLineTree : public CRangUpdateLineTree<TSave, TRecord>
{
public:
	CVectorRangeUpdateLineTree(int iEleSize, TSave tDefault, TRecord tRecordNull) :m_iEleSize(iEleSize), m_tDefault(tDefault)
		, m_save(iEleSize * 4, tDefault), m_record(iEleSize * 4, tRecordNull) {
		m_recordNull = tRecordNull;
	}
	void Update(int iLeftIndex, int iRightIndex, TRecord value)
	{
		Update(1, 0, m_iEleSize - 1, iLeftIndex, iRightIndex, value);
	}
	TSave Query(int leftIndex, int rightIndex) {
		return Query(leftIndex, rightIndex, m_tDefault);
	}
	TSave Query(int leftIndex, int rightIndex, const TSave& tDefault) {
		TSave ans = tDefault;
		Query(ans, 1, 0, m_iEleSize - 1, leftIndex, rightIndex);
		return ans;
	}
	//void Init() {
	//	Init(1, 0, m_iEleSize - 1);
	//}
	TSave QueryAll() {
		return m_save[1];
	}
	void swap(CVectorRangeUpdateLineTree<TSave, TRecord>& other) {
		m_save.swap(other.m_save);
		m_record.swap(other.m_record);
		std::swap(m_recordNull, other.m_recordNull);
		assert(m_iEleSize == other.m_iEleSize);
	}
protected:
	//void Init(int iNodeNO, int iSaveLeft, int iSaveRight)
	//{
	//	if (iSaveLeft == iSaveRight) {
	//		this->OnInit(m_save[iNodeNO], iSaveLeft);
	//		return;
	//	}
	//	const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;
	//	Init(iNodeNO * 2, iSaveLeft, mid);
	//	Init(iNodeNO * 2 + 1, mid + 1, iSaveRight);
	//	this->OnUpdateParent(m_save[iNodeNO], m_save[iNodeNO * 2], m_save[iNodeNO * 2 + 1], iSaveLeft, iSaveRight);
	//}
	void Query(TSave& ans, int iNodeNO, int iSaveLeft, int iSaveRight, int iQueryLeft, int iQueryRight) {
		if ((iSaveLeft >= iQueryLeft) && (iSaveRight <= iQueryRight)) {
			this->OnQuery(ans, m_save[iNodeNO], iSaveLeft, iSaveRight);
			return;
		}
		if (iSaveLeft == iSaveRight) {//没有子节点
			return;
		}
		Fresh(iNodeNO, iSaveLeft, iSaveRight);
		const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;
		if (mid >= iQueryLeft) {
			Query(ans, iNodeNO * 2, iSaveLeft, mid, iQueryLeft, iQueryRight);
		}
		if (mid + 1 <= iQueryRight) {
			Query(ans, iNodeNO * 2 + 1, mid + 1, iSaveRight, iQueryLeft, iQueryRight);
		}
	}
	void Update(int iNode, int iSaveLeft, int iSaveRight, int iOpeLeft, int iOpeRight, TRecord value)
	{
		if ((iOpeLeft <= iSaveLeft) && (iOpeRight >= iSaveRight))
		{
			this->OnUpdate(m_save[iNode], iSaveLeft, iSaveRight, value);
			this->OnUpdateRecord(m_record[iNode], value);
			return;
		}
		if (iSaveLeft == iSaveRight) {
			return;//没有子节点
		}
		Fresh(iNode, iSaveLeft, iSaveRight);
		const int iMid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;
		if (iMid >= iOpeLeft)
		{
			Update(iNode * 2, iSaveLeft, iMid, iOpeLeft, iOpeRight, value);
		}
		if (iMid + 1 <= iOpeRight)
		{
			Update(iNode * 2 + 1, iMid + 1, iSaveRight, iOpeLeft, iOpeRight, value);
		}
		// 如果有后代,至少两个后代
		this->OnUpdateParent(m_save[iNode], m_save[iNode * 2], m_save[iNode * 2 + 1], iSaveLeft, iSaveRight);
	}
	void Fresh(int iNode, int iDataLeft, int iDataRight)
	{
		if (m_recordNull == m_record[iNode])
		{
			return;
		}
		const int iMid = iDataLeft + (iDataRight - iDataLeft) / 2;
		Update(iNode * 2, iDataLeft, iMid, iDataLeft, iMid, m_record[iNode]);
		Update(iNode * 2 + 1, iMid + 1, iDataRight, iMid + 1, iDataRight, m_record[iNode]);
		m_record[iNode] = m_recordNull;
	}
	vector<TSave> m_save;
	vector<TRecord> m_record;
	TRecord m_recordNull;
	TSave m_tDefault;
	const int m_iEleSize;
};

template<class TSave, class TRecord >
class CTreeRangeLineTree : public CRangUpdateLineTree<TSave, TRecord>
{
protected:
	struct CTreeNode
	{
		int Cnt()const { return m_iMaxIndex - m_iMinIndex + 1; }
		int m_iMinIndex;
		int m_iMaxIndex;
		TRecord record;
		TSave data;
		CTreeNode* m_lChild = nullptr, * m_rChild = nullptr;
	};
	CTreeNode* m_root;
	TSave m_tDefault;
	TRecord m_tRecordDef;
public:
	CTreeRangeLineTree(int iMinIndex, int iMaxIndex, TSave tDefault, TRecord tRecordDef) {
		m_tDefault = tDefault;
		m_tRecordDef = tRecordDef;
		m_root = CreateNode(iMinIndex, iMaxIndex);
	}
	void Update(int iLeftIndex, int iRightIndex, TRecord value)
	{
		Update(m_root, iLeftIndex, iRightIndex, value);
	}
	TSave QueryAll() {
		return m_root->data;
	}
	TSave Query(int leftIndex, int leftRight) {
		TSave ans = m_tDefault;
		Query(ans, m_root, leftIndex, leftRight);
		return ans;
	}
protected:
	void Query(TSave& ans, CTreeNode* node, int iQueryLeft, int iQueryRight) {
		if ((node->m_iMinIndex >= iQueryLeft) && (node->m_iMaxIndex <= iQueryRight)) {
			this->OnQuery(ans, node->data, node->m_iMinIndex, node->m_iMaxIndex);
			return;
		}
		if (1 == node->Cnt()) {//没有子节点
			return;
		}
		CreateChilds(node);
		Fresh(node);
		const int mid = node->m_iMinIndex + (node->m_iMaxIndex - node->m_iMinIndex) / 2;
		if (mid >= iQueryLeft) {
			Query(ans, node->m_lChild, iQueryLeft, iQueryRight);
		}
		if (mid + 1 <= iQueryRight) {
			Query(ans, node->m_rChild, iQueryLeft, iQueryRight);
		}
	}
	void Update(CTreeNode* node, int iOpeLeft, int iOpeRight, TRecord value)
	{
		const int& iSaveLeft = node->m_iMinIndex;
		const int& iSaveRight = node->m_iMaxIndex;
		if ((iOpeLeft <= iSaveLeft) && (iOpeRight >= iSaveRight))
		{
			this->OnUpdate(node->data, iSaveLeft, iSaveRight, value);
			this->OnUpdateRecord(node->record, value);
			return;
		}
		if (1 == node->Cnt()) {//没有子节点
			return;
		}
		CreateChilds(node);
		Fresh(node);
		const int mid = node->m_iMinIndex + (node->m_iMaxIndex - node->m_iMinIndex) / 2;
		if (mid >= iOpeLeft) {
			this->Update(node->m_lChild, iOpeLeft, iOpeRight, value);
		}
		if (mid + 1 <= iOpeRight) {
			this->Update(node->m_rChild, iOpeLeft, iOpeRight, value);
		}
		// 如果有后代,至少两个后代
		this->OnUpdateParent(node->data, node->m_lChild->data, node->m_rChild->data, node->m_iMinIndex, node->m_iMaxIndex);
	}
	void CreateChilds(CTreeNode* node) {
		if (nullptr != node->m_lChild) { return; }
		const int iSaveLeft = node->m_iMinIndex;
		const int iSaveRight = node->m_iMaxIndex;
		const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;
		node->m_lChild = CreateNode(iSaveLeft, mid);
		node->m_rChild = CreateNode(mid + 1, iSaveRight);
	}
	CTreeNode* CreateNode(int iMinIndex, int iMaxIndex) {
		CTreeNode* node = new CTreeNode;
		node->m_iMinIndex = iMinIndex;
		node->m_iMaxIndex = iMaxIndex;
		node->data = m_tDefault;
		node->record = m_tRecordDef;
		return node;
	}
	void Fresh(CTreeNode* node)
	{
		if (m_tRecordDef == node->record)
		{
			return;
		}
		CreateChilds(node);
		Update(node->m_lChild, node->m_lChild->m_iMinIndex, node->m_lChild->m_iMaxIndex, node->record);
		Update(node->m_rChild, node->m_rChild->m_iMinIndex, node->m_rChild->m_iMaxIndex, node->record);
		node->record = m_tRecordDef;
	}
};

typedef long long TSave;
typedef pair<long long, long long>  TRecord;
class  CMyLineTree : public  CVectorRangeUpdateLineTree<TSave, TRecord>
{
public:
	using CVectorRangeUpdateLineTree::CVectorRangeUpdateLineTree;
protected:
	virtual void OnQuery(TSave& ans, const TSave& save, const int& iSaveLeft, const int& iSaveRight) {
		ans += save;
	}
	virtual void OnUpdate(TSave& save, const int& iSaveLeft, const int& iSaveRight, const TRecord& update) override
	{
		save += iSaveLeft * update.first + update.second;
	}
	virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r, const int& iSaveLeft, const int& iSaveRight)  override
	{

	}
	virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) override
	{
		old.first += newRecord.first;
		old.second += newRecord.second;
	}
};
class Solution {
public:
	vector<long long> Ans(const int M, vector<pair<int, int>>& ope) {
		CMyLineTree lineTree(M + 1, 0, { 0,0 });
		auto Update = [&](int left, int r, int lval, long long d) {
			const int l1 = max(left, 0);
			const int r1 = min(r, M);
			if (r1 < l1) { return; }
			r = min(r, M);
			if (left < 0) {
				lval += (0 - left) * d;
				left = 0;
			}
			lineTree.Update(left, r, { d,lval - left * d });
		};
		for (const auto& [v, i] : ope) {
			Update(i, i + 2 * v, -v, 1);
			Update(i + 2 * v + 1, i + 3 * v, v - 1, -1);
			Update(i - 2 * v, i - 1, v, -1);
			Update(i - 3 * v, i - (2 * v + 1), 0, 1);
		}
		vector<long long> ans;
		for (int i = 1; i <= M; i++) {
			ans.emplace_back(lineTree.Query(i, i));
		}
		return ans;
	}
};

int main() {	
#ifdef _DEBUG
	freopen("a.in", "r", stdin);
#endif // DEBUG		
	int n,m;
	cin >> n >> m;
	auto ope = Read<pair<int,int>>(n);
		auto res = Solution().Ans(m,ope);
#ifdef _DEBUG		
		/*printf("T=%d,", T);*/
	/*	Out(ope, "ope=");
		Out(res, "res=");*/
		/*Out(que, "que=");*/
#endif // DEBUG	
		COutBuff bf;
		for (const auto& i : res )
		{			
			bf.write(i);
			bf.write(' ');
		}
	return 0;
}

差分数组

∀ \forall i ∈ \in [left,r] 增加k × \times ×i+d。对 ∀ \forall i,分别统计k之和sk,d之和sd。然后sk × \times ×i+sd。
时间复杂度:O(n)

代码

#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>

#include <bitset>
using namespace std;

template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {
	in >> pr.first >> pr.second;
	return in;
}

template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t);
	return in;
}

template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
	return in;
}

template<class T = int>
vector<T> Read() {
	int n;
	scanf("%d", &n);
	vector<T> ret(n);
	for (int i = 0; i < n; i++) {
		cin >> ret[i];
	}
	return ret;
}

template<class T = int>
vector<T> Read(int n) {
	vector<T> ret(n);
	for (int i = 0; i < n; i++) {
		cin >> ret[i];
	}
	return ret;
}

template<int N = 1'000'000>
class COutBuff
{
public:
	COutBuff() {
		m_p = puffer;
	}
	template<class T>
	void write(T x) {
		int num[28], sp = 0;
		if (x < 0)
			*m_p++ = '-', x = -x;

		if (!x)
			*m_p++ = 48;

		while (x)
			num[++sp] = x % 10, x /= 10;

		while (sp)
			*m_p++ = num[sp--] + 48;
		AuotToFile();
	}
	inline void write(char ch)
	{
		*m_p++ = ch;
		AuotToFile();
	}
	inline void ToFile() {
		fwrite(puffer, 1, m_p - puffer, stdout);
		m_p = puffer;
	}	
	~COutBuff() {
		ToFile();
	}
private:
	inline void AuotToFile() {
		if (m_p - puffer > N - 100) {
			ToFile();
		}
	}
	char  puffer[N], * m_p;
};

template<int N = 12 * 1'000'000>
class CInBuff
{
public:
	inline CInBuff() {
		fread(buffer, 1, N, stdin);
	}
	inline int Read() {
		int x(0), f(0);
		while (!isdigit(*S))
			f |= (*S++ == '-');
		while (isdigit(*S))
			x = (x << 1) + (x << 3) + (*S++ ^ 48);
		return f ? -x : x;
	}
private:
	char buffer[N], * S = buffer;
};

template<class TSave, class TRecord >
class CRangUpdateLineTree
{
protected:
	virtual void OnQuery(TSave& ans, const TSave& save, const int& iSaveLeft, const int& iSaveRight) = 0;
	virtual void OnUpdate(TSave& save, const int& iSaveLeft, const int& iSaveRight, const TRecord& update) = 0;
	virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r, const int& iSaveLeft, const int& iSaveRight) = 0;
	virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) = 0;
};

template<class TSave, class TRecord >
class CVectorRangeUpdateLineTree : public CRangUpdateLineTree<TSave, TRecord>
{
public:
	CVectorRangeUpdateLineTree(int iEleSize, TSave tDefault, TRecord tRecordNull) :m_iEleSize(iEleSize), m_tDefault(tDefault)
		, m_save(iEleSize * 4, tDefault), m_record(iEleSize * 4, tRecordNull) {
		m_recordNull = tRecordNull;
	}
	void Update(int iLeftIndex, int iRightIndex, TRecord value)
	{
		Update(1, 0, m_iEleSize - 1, iLeftIndex, iRightIndex, value);
	}
	TSave Query(int leftIndex, int rightIndex) {
		return Query(leftIndex, rightIndex, m_tDefault);
	}
	TSave Query(int leftIndex, int rightIndex, const TSave& tDefault) {
		TSave ans = tDefault;
		Query(ans, 1, 0, m_iEleSize - 1, leftIndex, rightIndex);
		return ans;
	}
	//void Init() {
	//	Init(1, 0, m_iEleSize - 1);
	//}
	TSave QueryAll() {
		return m_save[1];
	}
	void swap(CVectorRangeUpdateLineTree<TSave, TRecord>& other) {
		m_save.swap(other.m_save);
		m_record.swap(other.m_record);
		std::swap(m_recordNull, other.m_recordNull);
		assert(m_iEleSize == other.m_iEleSize);
	}
protected:
	//void Init(int iNodeNO, int iSaveLeft, int iSaveRight)
	//{
	//	if (iSaveLeft == iSaveRight) {
	//		this->OnInit(m_save[iNodeNO], iSaveLeft);
	//		return;
	//	}
	//	const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;
	//	Init(iNodeNO * 2, iSaveLeft, mid);
	//	Init(iNodeNO * 2 + 1, mid + 1, iSaveRight);
	//	this->OnUpdateParent(m_save[iNodeNO], m_save[iNodeNO * 2], m_save[iNodeNO * 2 + 1], iSaveLeft, iSaveRight);
	//}
	void Query(TSave& ans, int iNodeNO, int iSaveLeft, int iSaveRight, int iQueryLeft, int iQueryRight) {
		if ((iSaveLeft >= iQueryLeft) && (iSaveRight <= iQueryRight)) {
			this->OnQuery(ans, m_save[iNodeNO], iSaveLeft, iSaveRight);
			return;
		}
		if (iSaveLeft == iSaveRight) {//没有子节点
			return;
		}
		Fresh(iNodeNO, iSaveLeft, iSaveRight);
		const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;
		if (mid >= iQueryLeft) {
			Query(ans, iNodeNO * 2, iSaveLeft, mid, iQueryLeft, iQueryRight);
		}
		if (mid + 1 <= iQueryRight) {
			Query(ans, iNodeNO * 2 + 1, mid + 1, iSaveRight, iQueryLeft, iQueryRight);
		}
	}
	void Update(int iNode, int iSaveLeft, int iSaveRight, int iOpeLeft, int iOpeRight, TRecord value)
	{
		if ((iOpeLeft <= iSaveLeft) && (iOpeRight >= iSaveRight))
		{
			this->OnUpdate(m_save[iNode], iSaveLeft, iSaveRight, value);
			this->OnUpdateRecord(m_record[iNode], value);
			return;
		}
		if (iSaveLeft == iSaveRight) {
			return;//没有子节点
		}
		Fresh(iNode, iSaveLeft, iSaveRight);
		const int iMid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;
		if (iMid >= iOpeLeft)
		{
			Update(iNode * 2, iSaveLeft, iMid, iOpeLeft, iOpeRight, value);
		}
		if (iMid + 1 <= iOpeRight)
		{
			Update(iNode * 2 + 1, iMid + 1, iSaveRight, iOpeLeft, iOpeRight, value);
		}
		// 如果有后代,至少两个后代
		this->OnUpdateParent(m_save[iNode], m_save[iNode * 2], m_save[iNode * 2 + 1], iSaveLeft, iSaveRight);
	}
	void Fresh(int iNode, int iDataLeft, int iDataRight)
	{
		if (m_recordNull == m_record[iNode])
		{
			return;
		}
		const int iMid = iDataLeft + (iDataRight - iDataLeft) / 2;
		Update(iNode * 2, iDataLeft, iMid, iDataLeft, iMid, m_record[iNode]);
		Update(iNode * 2 + 1, iMid + 1, iDataRight, iMid + 1, iDataRight, m_record[iNode]);
		m_record[iNode] = m_recordNull;
	}
	vector<TSave> m_save;
	vector<TRecord> m_record;
	TRecord m_recordNull;
	TSave m_tDefault;
	const int m_iEleSize;
};

template<class TSave, class TRecord >
class CTreeRangeLineTree : public CRangUpdateLineTree<TSave, TRecord>
{
protected:
	struct CTreeNode
	{
		int Cnt()const { return m_iMaxIndex - m_iMinIndex + 1; }
		int m_iMinIndex;
		int m_iMaxIndex;
		TRecord record;
		TSave data;
		CTreeNode* m_lChild = nullptr, * m_rChild = nullptr;
	};
	CTreeNode* m_root;
	TSave m_tDefault;
	TRecord m_tRecordDef;
public:
	CTreeRangeLineTree(int iMinIndex, int iMaxIndex, TSave tDefault, TRecord tRecordDef) {
		m_tDefault = tDefault;
		m_tRecordDef = tRecordDef;
		m_root = CreateNode(iMinIndex, iMaxIndex);
	}
	void Update(int iLeftIndex, int iRightIndex, TRecord value)
	{
		Update(m_root, iLeftIndex, iRightIndex, value);
	}
	TSave QueryAll() {
		return m_root->data;
	}
	TSave Query(int leftIndex, int leftRight) {
		TSave ans = m_tDefault;
		Query(ans, m_root, leftIndex, leftRight);
		return ans;
	}
protected:
	void Query(TSave& ans, CTreeNode* node, int iQueryLeft, int iQueryRight) {
		if ((node->m_iMinIndex >= iQueryLeft) && (node->m_iMaxIndex <= iQueryRight)) {
			this->OnQuery(ans, node->data, node->m_iMinIndex, node->m_iMaxIndex);
			return;
		}
		if (1 == node->Cnt()) {//没有子节点
			return;
		}
		CreateChilds(node);
		Fresh(node);
		const int mid = node->m_iMinIndex + (node->m_iMaxIndex - node->m_iMinIndex) / 2;
		if (mid >= iQueryLeft) {
			Query(ans, node->m_lChild, iQueryLeft, iQueryRight);
		}
		if (mid + 1 <= iQueryRight) {
			Query(ans, node->m_rChild, iQueryLeft, iQueryRight);
		}
	}
	void Update(CTreeNode* node, int iOpeLeft, int iOpeRight, TRecord value)
	{
		const int& iSaveLeft = node->m_iMinIndex;
		const int& iSaveRight = node->m_iMaxIndex;
		if ((iOpeLeft <= iSaveLeft) && (iOpeRight >= iSaveRight))
		{
			this->OnUpdate(node->data, iSaveLeft, iSaveRight, value);
			this->OnUpdateRecord(node->record, value);
			return;
		}
		if (1 == node->Cnt()) {//没有子节点
			return;
		}
		CreateChilds(node);
		Fresh(node);
		const int mid = node->m_iMinIndex + (node->m_iMaxIndex - node->m_iMinIndex) / 2;
		if (mid >= iOpeLeft) {
			this->Update(node->m_lChild, iOpeLeft, iOpeRight, value);
		}
		if (mid + 1 <= iOpeRight) {
			this->Update(node->m_rChild, iOpeLeft, iOpeRight, value);
		}
		// 如果有后代,至少两个后代
		this->OnUpdateParent(node->data, node->m_lChild->data, node->m_rChild->data, node->m_iMinIndex, node->m_iMaxIndex);
	}
	void CreateChilds(CTreeNode* node) {
		if (nullptr != node->m_lChild) { return; }
		const int iSaveLeft = node->m_iMinIndex;
		const int iSaveRight = node->m_iMaxIndex;
		const int mid = iSaveLeft + (iSaveRight - iSaveLeft) / 2;
		node->m_lChild = CreateNode(iSaveLeft, mid);
		node->m_rChild = CreateNode(mid + 1, iSaveRight);
	}
	CTreeNode* CreateNode(int iMinIndex, int iMaxIndex) {
		CTreeNode* node = new CTreeNode;
		node->m_iMinIndex = iMinIndex;
		node->m_iMaxIndex = iMaxIndex;
		node->data = m_tDefault;
		node->record = m_tRecordDef;
		return node;
	}
	void Fresh(CTreeNode* node)
	{
		if (m_tRecordDef == node->record)
		{
			return;
		}
		CreateChilds(node);
		Update(node->m_lChild, node->m_lChild->m_iMinIndex, node->m_lChild->m_iMaxIndex, node->record);
		Update(node->m_rChild, node->m_rChild->m_iMinIndex, node->m_rChild->m_iMaxIndex, node->record);
		node->record = m_tRecordDef;
	}
};

typedef long long TSave;
typedef pair<long long, long long>  TRecord;
class  CMyLineTree : public  CVectorRangeUpdateLineTree<TSave, TRecord>
{
public:
	using CVectorRangeUpdateLineTree::CVectorRangeUpdateLineTree;
protected:
	virtual void OnQuery(TSave& ans, const TSave& save, const int& iSaveLeft, const int& iSaveRight) {
		ans += save;
	}
	virtual void OnUpdate(TSave& save, const int& iSaveLeft, const int& iSaveRight, const TRecord& update) override
	{
		save += iSaveLeft * update.first + update.second;
	}
	virtual void OnUpdateParent(TSave& par, const TSave& left, const TSave& r, const int& iSaveLeft, const int& iSaveRight)  override
	{

	}
	virtual void OnUpdateRecord(TRecord& old, const TRecord& newRecord) override
	{
		old.first += newRecord.first;
		old.second += newRecord.second;
	}
};
class Solution {
public:
	vector<long long> Ans(const int M, vector<pair<int, int>>& ope) {
		vector<long long> diff1(M + 2), diff2(M + 2);
		auto Update = [&](int left, int r, int lval, long long d) {
			const int l1 = max(left, 1);
			const int r1 = min(r, M);
			if (r1 < l1) { return; }
			r = min(r, M);
			if (left < 1) {
				lval += (1 - left) * d;
				left = 1;
			}
			diff1[left] += d; diff1[r + 1] -= d;
			diff2[left] += lval - left * d; diff2[r + 1] -= lval - left * d;
		};
		for (const auto& [v, i] : ope) {
			Update(i, i + 2 * v, -v, 1);
			Update(i + 2 * v + 1, i + 3 * v, v - 1, -1);
			Update(i - 2 * v, i - 1, v, -1);
			Update(i - 3 * v, i - (2 * v + 1), 0, 1);
		}
		vector<long long> ans;
		long long cur1 = 0, cur2 = 0;
		for (int i = 1; i <= M; i++) {
			cur1 += diff1[i];
			cur2 += diff2[i];
			ans.emplace_back(cur1 * i + cur2);
		}
		return ans;
	}
};

int main() {	
#ifdef _DEBUG
	freopen("a.in", "r", stdin);
#endif // DEBUG		
	int n,m;
	cin >> n >> m;
	auto ope = Read<pair<int,int>>(n);
		auto res = Solution().Ans(m,ope);
#ifdef _DEBUG		
		/*printf("T=%d,", T);*/
	/*	Out(ope, "ope=");
		Out(res, "res=");*/
		/*Out(que, "que=");*/
#endif // DEBUG	
		COutBuff bf;
		for (const auto& i : res )
		{			
			bf.write(i);
			bf.write(' ');
		}
	return 0;
}

单元测试

vector<int> a;
		vector<pair<int, int>> ope;
		TEST_METHOD(TestMethod11)		{
			ope = { {1,5} };
			auto res = Solution().Ans(10,ope);
			AssertEx({ 0,0,1,0,-1,0,1,0,0,0 }, res);
		}
		TEST_METHOD(TestMethod12) {
			ope = { {2,6},{3,1} };
			auto res = Solution().Ans(10, ope);
			AssertEx({ -2,0,0,0,0,0,2,2,2,2 }, res);
		}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

软件架构师何志丹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值