【动态规划】【滑动窗口】【C++算法】 629K 个逆序对数组

作者推荐

【矩阵快速幂】封装类及测试用例及样例

本文涉及知识点

动态规划
C++算法:滑动窗口总结

LeetCode629: K 个逆序对数组

逆序对的定义如下:对于数组 nums 的第 i 个和第 j 个元素,如果满足 0 <= i < j < nums.length 且 nums[i] > nums[j],则其为一个逆序对;否则不是。
给你两个整数 n 和 k,找出所有包含从 1 到 n 的数字,且恰好拥有 k 个 逆序对 的不同的数组的个数。由于答案可能很大,只需要返回对 109 + 7 取余的结果。
示例 1:
输入:n = 3, k = 0
输出:1
解释:
只有数组 [1,2,3] 包含了从1到3的整数并且正好拥有 0 个逆序对。
示例 2:
输入:n = 3, k = 1
输出:2
解释:
数组 [1,3,2] 和 [2,1,3] 都有 1 个逆序对。
提示:
1 <= n <= 1000
0 <= k <= 1000

动态规划

** 空间复杂度**: O(n)
时间复杂度😮(n2)
动态规划的状态表示:pre[i]表示1到j-1的排列中,逆数对数量为i的数量。dp[i]表示1到j的排列中,逆数对的数量。 i 取值范围[0,1000]
动态规划的转移方程: 假定某个1到j-1 的排列,逆数对为x。插入j后,除j外的顺序不边,也就是除j外,不会产生新的逆数对。当然也不会减少逆数对。那如果将j插入到最后,逆序数不变。插入到倒数第一之前,逆数对+1。。。插入到最前面,逆序对+j-1。换过说法:
dp[i] = Sum ( i − j , i ] k ^{k}_{(i-j,i]} (ij,i]kpre[k]。 可以利用滑动窗口求和。
动态规划的初始状态: pre[0]=0
动态规划的填表顺序: j 从小到大,i从小到大。
动态规划的返回值:pre[k]

代码

使用到的类库

template<int MOD = 1000000007>
class C1097Int
{
public:
	C1097Int(long long llData = 0) :m_iData(llData% MOD)
	{

	}
	C1097Int  operator+(const C1097Int& o)const
	{
		return C1097Int(((long long)m_iData + o.m_iData) % MOD);
	}
	C1097Int& operator+=(const C1097Int& o)
	{
		m_iData = ((long long)m_iData + o.m_iData) % MOD;
		return *this;
	}
	C1097Int& operator-=(const C1097Int& o)
	{
		m_iData = (m_iData + MOD - o.m_iData) % MOD;
		return *this;
	}
	C1097Int  operator-(const C1097Int& o)
	{
		return C1097Int((m_iData + MOD - o.m_iData) % MOD);
	}
	C1097Int  operator*(const C1097Int& o)const
	{
		return((long long)m_iData * o.m_iData) % MOD;
	}
	C1097Int& operator*=(const C1097Int& o)
	{
		m_iData = ((long long)m_iData * o.m_iData) % MOD;
		return *this;
	}
	bool operator<(const C1097Int& o)const
	{
		return m_iData < o.m_iData;
	}
	C1097Int pow(long long n)const
	{
		C1097Int iRet = 1, iCur = *this;
		while (n)
		{
			if (n & 1)
			{
				iRet *= iCur;
			}
			iCur *= iCur;
			n >>= 1;
		}
		return iRet;
	}
	C1097Int PowNegative1()const
	{
		return pow(MOD - 2);
	}
	int ToInt()const
	{
		return m_iData;
	}
private:
	int m_iData = 0;;
};

核心代码

class Solution {
public:
	int kInversePairs(int n, int k) {
		vector<C1097Int<>> pre(1001) ;
		pre[0] = 1;
		for (int j = 2; j <= n; j++)
		{
			vector<C1097Int<>> dp(1001);
			C1097Int<> iSum = 0;
			for (int i = 0; i < pre.size(); i++)
			{
				iSum += pre[i];
				if (i - j >= 0)
				{
					iSum -= pre[i - j];
				}
				dp[i] = iSum;
			}
			pre.swap(dp);
		}
		return pre[k].ToInt();
	}
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		Assert(v1[i], v2[i]);
	}
}


int main()
{
	int n,k;
	{
		Solution sln;
		n = 3, k = 0;
		auto res = sln.kInversePairs(n, k);
		Assert(1, res);
	}
	{
		Solution sln;
		n = 3, k = 1;
		auto res = sln.kInversePairs(n, k);
		Assert(2, res);
	}

	{
		Solution sln;
		n = 1000, k = 1000;
		auto res = sln.kInversePairs(n, k);
		Assert(663677020, res);
	}
}

2023年1月版

class CBigMath
{
public:
static void AddAssignment(int* dst, const int& iSrc)
{
*dst = (*dst + iSrc) % s_iMod;
}

 static void AddAssignment(int* dst, const int& iSrc, const int& iSrc1)
 {
	 *dst = (*dst + iSrc) % s_iMod;
	 *dst = (*dst + iSrc1) % s_iMod;
 }

 static void AddAssignment(int* dst, const int& iSrc, const int& iSrc1, const int& iSrc2)
 {
	 *dst = (*dst + iSrc) % s_iMod;
	 *dst = (*dst + iSrc1) % s_iMod;
	 *dst = (*dst + iSrc2) % s_iMod;
 }

 static void SubAssignment(int* dst, const int& iSrc)
 {
	 *dst = (s_iMod - iSrc + *dst) % s_iMod;
 }
 static int Add(const int& iAdd1, const int& iAdd2)
 {
	 return (iAdd1 + iAdd2) % s_iMod;
 }
 static int Mul(const int& i1, const int& i2)
 {
	 return((long long)i1 *i2) % s_iMod;
 }

private:
static const int s_iMod = 1000000007;
};

class Solution {
public:
int kInversePairs(int n, int k) {
vector preDp(k + 1);
preDp[0] = 1;
for (int i = 2; i <= n; i++)
{
vector dp(k+1 );
for (int j = 0; j < dp.size(); j++)
{
if (j < preDp.size())
{
CBigMath::AddAssignment(&dp[j], preDp[j]);
}
if (j > 0)
{
CBigMath::AddAssignment(&dp[j], dp[j - 1]);
}
if ( j - i >= 0)
{
int iMod = 1000000007;
CBigMath::AddAssignment(&dp[j], iMod - preDp[j - i]);
}
}
preDp.swap(dp);
}
return k >= preDp.size() ? 0 : preDp[k];
}
};

2023年6月

using namespace std;

template
void OutToConsoleInner(const vector& vec,const string& strSep = " ")
{
for (int i = 0; i < vec.size(); i++)
{
if (0 != i%25)
{
std::cout << strSep.c_str();
}
std::cout << setw(3) << setfill(’ ') << vec[i];
if (0 == (i+1) % 25)
{
std::cout << std::endl;
}
else if (0 == (i + 1) % 5)
{
std::cout << strSep.c_str();
}
}
}

class CConsole
{
public :

template<class T>
static void Out(const vector<T>& vec, const string& strColSep = " ", const string& strRowSep = "\r\n")
{
	OutToConsoleInner(vec, strColSep);
	std::cout << strRowSep.c_str();
}

template<class T>
static void Out(const vector<vector<T>>& matrix, const string& strColSep = " ", const string& strRowSep = "\r\n")
{
	for (int i = 0; i < matrix.size(); i++)
	{
		OutToConsoleInner(matrix[i], strColSep);
		std::cout << strRowSep.c_str();
	}
}

template<class T>
static void Out(const std::map<T, std::vector<int> >& mTopPointToPoints, const string& strColSep = " ", const string& strRowSep = "\r\n")
{
	for (auto kv : mTopPointToPoints)
	{
		std::cout << kv.first << ":";
		OutToConsoleInner(kv.second, strColSep);
		std::cout << strRowSep.c_str();
	}
}


static void Out(const  std::string& t, const string& strColSep = " ", const string& strRowSep = "\r\n")
{
	std::cout << t.c_str() << strColSep.c_str();
}

template<class T  >
static void Out(const T& t, const string& strColSep = " ", const string& strRowSep = "\r\n")
{
	std::cout << t << strColSep.c_str();
}

};

void GenetateSum(vector& sums, const vector& nums)
{
sums.push_back(0);
for (int i = 0; i < nums.size(); i++)
{
sums.push_back(nums[i] + sums[i]);
}
}

//[iBegin,iEnd]之和
long long Total(int iBegin,int iEnd)
{
return (long long)(iBegin + iEnd)*(iEnd - iBegin + 1) / 2;
}

class CLadderhlp
{
public:
CLadderhlp( int ladders)
{
m_uLadderNum = ladders;
}
void AddNeedBick(int iNeedBick)
{
if (0 == m_uLadderNum)
{
return;
}
if (m_ladders.size() < m_uLadderNum)
{
m_ladders.push(iNeedBick);
m_iEaqualBicks += iNeedBick;
return;
}
int iTop = m_ladders.top();
if (iTop >= iNeedBick)
{
return;
}
m_iEaqualBicks -= iTop;
m_iEaqualBicks += iNeedBick;
m_ladders.pop();
m_ladders.push(iNeedBick);
}
std::priority_queue<int,vector,std::greater > m_ladders;
unsigned int m_uLadderNum;
long long m_iEaqualBicks = 0;
};

struct CPeo
{
CPeo(string strName, CPeo* pParent=nullptr)
{
m_strName = strName;
m_pParent = pParent;
}
string m_strName;
vector<CPeo*> m_childs;
CPeo* m_pParent = nullptr;
};

class CNeighborTable
{
public:
void Init(const vector<vector>& edges)
{

 }
 vector<vector<int>> m_vTable;

};

//通过 x &= (x-1)实现
int bitcount(unsigned x) {
int countx = 0;
while (x) {
countx++;
x &= (x - 1);
}
return countx;
}

int bitcount(unsigned long long x) {
int countx = 0;
while (x) {
countx++;
x &= (x - 1);
}
return countx;
}

class CRange
{
public:
template
CRange(const T& v)
{
m_iBegin = 0;
m_iEnd = v.size();
}
bool In(int iIndex)
{
return (iIndex >= m_iBegin) && (iIndex < m_iEnd);
}
const int End()
{
return m_iEnd;
}
protected:
int m_iBegin;
int m_iEnd;
};

template
class CTrie
{
public:
CTrie() :m_vPChilds(iTypeNum)
{

 }
 template<class IT>
 void Add(IT begin, IT end)
 {
	 CTrie<iTypeNum, cBegin> * pNode = this;
	 for (; begin != end; ++begin)
	 {
		 pNode = pNode->AddChar(*begin).get();
	 }
 }
 template<class IT>
 bool Search(IT begin, IT end)
 {
	 if (begin == end)
	 {
		 return true;
	 }

	 if ('.' == *begin)
	 {
		 for (auto& ptr : m_vPChilds)
		 {
			 if (!ptr)
			 {
				 continue;
			 }
			 if (ptr->Search(begin + 1, end))
			 {
				 return true;
			 }
		 }
	 }

	 auto ptr = GetChild(*begin);
	 if (nullptr == ptr)
	 {
		 return false;
	 }
	 return ptr->Search(begin + 1, end);
 }

protected:
std::shared_ptr AddChar(char ch)
{
if ((ch < cBegin) || (ch >= cBegin + iTypeNum))
{
return nullptr;
}
const int index = ch - cBegin;
auto ptr = m_vPChilds[index];
if (!ptr)
{
m_vPChilds[index] = std::make_shared<CTrie<iTypeNum, cBegin>>();
}
return m_vPChilds[index];
}
std::shared_ptr GetChild(char ch)const
{
if ((ch < cBegin) || (ch >= cBegin + iTypeNum))
{
return nullptr;
}
return m_vPChilds[ch - cBegin];
}
std::vector<std::shared_ptr> m_vPChilds;
};

class CWords
{
public:
void Add(const string& word)
{
m_strStrs.insert(word);
}
bool Search(const string& word)
{
return Search(m_strStrs.begin(), m_strStrs.end(), 0, word.length(), word);
}
protected:
bool Search(std::set::const_iterator begin, std::set::const_iterator end, int iStrBegin, int iStrEnd, const string& str)
{
int i = iStrBegin;
for (; (i < iStrEnd) && (str[i] != ‘.’); i++);
auto it = std::equal_range(begin, end, str, [&iStrBegin, &i](const string& s, const string& sFind)
{
return s.substr(iStrBegin, i - iStrBegin) < sFind.substr(iStrBegin, i - iStrBegin);
});
if (i == iStrBegin)
{
it.first = begin;
it.second = end;
}
if (it.first == it.second)
{
return false;
}
if (i == iStrEnd)
{
return true;
}
if (i + 1 == iStrEnd)
{
return true;
}
string tmp = str;
for (char ch = ‘a’; ch <= ‘z’; ch++)
{
tmp[i] = ch;
auto ij = std::equal_range(it.first, it.second, tmp, [&ch, &i](const string& s, const string& sFind)
{
return s[i] < sFind[i];
});
if (ij.first == ij.second)
{
continue;
}

		 if (Search(ij.first, ij.second, i + 1, iStrEnd, str))
		 {
			 return true;
		 }
	 }
	 return false;
 }

 std::set<string> m_strStrs;

};
class WordDictionary {
public:
WordDictionary() {
for (int i = 0; i < 26; i++)
{
m_str[i] = std::make_unique();
}
}

 void addWord(string word) {
	 m_str[word.length()]->Add(word);
 }

 bool search(string word) {
	 return m_str[word.length()]->Search(word);
 }
 std::unique_ptr<CWords> m_str[26];

};

template
class C1097Int
{
public:
C1097Int(long long llData = 0) :m_iData(llData%MOD)
{

 }
 C1097Int  operator+(const C1097Int& o)const
 {
	 return C1097Int(((long long)m_iData + o.m_iData) % MOD);
 }
 C1097Int&  operator+=(const C1097Int& o)
 {
	 m_iData = ((long long)m_iData + o.m_iData) % MOD;
	 return *this;
 }
 C1097Int&  operator-=(const C1097Int& o)
 {
	 m_iData = (m_iData + MOD - o.m_iData) % MOD;
	 return *this;
 }
 C1097Int  operator-(const C1097Int& o)
 {
	 return C1097Int((m_iData + MOD - o.m_iData) % MOD);
 }
 C1097Int  operator*(const C1097Int& o)const
 {
	 return((long long)m_iData *o.m_iData) % MOD;
 }
 C1097Int&  operator*=(const C1097Int& o)
 {
	 m_iData = ((long long)m_iData *o.m_iData) % MOD;
	 return *this;
 }
 bool operator<(const C1097Int& o)const
 {
	 return m_iData < o.m_iData;
 }
 C1097Int pow( int n)const
 {
	 C1097Int iRet = 1, iCur = *this;
	while (n)
	{
		if (n & 1)
		{
			iRet *= iCur;
		}
		iCur *= iCur;
		n >>= 1;
	}
	return iRet;
 }
 C1097Int PowNegative1()const
 {
	 return pow(MOD - 2);
 }
 int ToInt()const
 {
	 return m_iData;
 }

private:
int m_iData = 0;;
};

template
int operator+(int iData, const C1097Int& int1097)
{
int iRet = int1097.operator+(C1097Int(iData)).ToInt();
return iRet;
}

template
int& operator+=(int& iData, const C1097Int& int1097)
{
iData = int1097.operator+(C1097Int(iData)).ToInt();
return iData;
}

template
int operator*(int iData, const C1097Int& int1097)
{
int iRet = int1097.operator*(C1097Int(iData)).ToInt();
return iRet;
}

template
int& operator*=(int& iData, const C1097Int& int1097)
{
iData = int1097.operator*(C1097Int(iData)).ToInt();
return iData;
}

template
void MinSelf(T* seft, const T& other)
{
*seft = min(*seft, other);
}

template
void MaxSelf(T* seft, const T& other)
{
*seft = max(*seft, other);
}

int GetNotRepeateNum(int len, int iHasSel)
{
if (0 == len)
{
return 1;
}
if ((0 == iHasSel) && (1 == len))
{
return 10;
}
int iRet = 1;
if (iHasSel > 0)
{
for (int tmp = 10 - iHasSel; (tmp >= 2)&& len ; tmp–,len–)
{
iRet *= tmp;
}
}
else
{
iRet *= 9;
len–;
for (int tmp=9; (tmp>=2)&&len; len–,tmp–)
{
iRet *= tmp;
}
}
return iRet;
}

int GCD(int n1, int n2)
{
int t1 = min(n1, n2);
int t2 = max(n1, n2);
if (0 == t1)
{
return t2;
}
return GCD(t2%t1, t1);
}

void CreateMaskVector(vector& v,const int* const p,int n )
{
const int iMaxMaskNum = 1 << n;
v.resize(iMaxMaskNum);
for (int i = 0; i < n; i++)
{
v[1 << i] = p[i];
}
for (int mask = 1; mask < iMaxMaskNum ; mask++)
{
const int iSubMask = mask&(-mask);
v[mask] = v[iSubMask] + v[mask-iSubMask];
}
}

class CMaxLineTree
{
public:
CMaxLineTree(int iArrSize) :m_iArrSize(iArrSize), m_vData(iArrSize * 4)
{

 }
 //iIndex 从0开始
 void Modify( int iIndex, int iValue)
 {
	 Modify(1, 1, m_iArrSize, iIndex + 1, iValue);
 }
 //iNeedQueryLeft iNeedQueryRight 从0开始
 int Query(const int iNeedQueryLeft, const int iNeedQueryRight)
 {
	 return Query(1, 1, m_iArrSize, iNeedQueryLeft + 1, iNeedQueryRight + 1);
 }

protected:
int Query(const int iTreeNodeIndex, const int iRecordLeft, const int iRecordRight, const int iNeedQueryLeft, const int iNeedQueryRight)
{
if ((iNeedQueryLeft <= iRecordLeft) && (iNeedQueryRight >= iRecordRight))
{
return m_vData[iTreeNodeIndex];
}
const int iMid = (iRecordLeft + iRecordRight) / 2;
int iRet = 0;
if (iNeedQueryLeft <= iMid)
{
iRet = Query(iTreeNodeIndex * 2, iRecordLeft, iMid, iNeedQueryLeft, iNeedQueryRight);
}
if (iNeedQueryRight > iMid)
{
iRet = max(iRet, Query(iTreeNodeIndex * 2 + 1, iMid + 1, iRecordRight, iNeedQueryLeft, iNeedQueryRight));
}
return iRet;
}
void Modify(int iTreeNodeIndex, int iLeft, int iRight, int iIndex, int iValue)
{
if (iLeft == iRight)
{
m_vData[iTreeNodeIndex] = max(m_vData[iTreeNodeIndex],iValue);
return;
}
const int iMid = (iLeft + iRight) / 2;
if (iIndex <= iMid)
{
Modify(iTreeNodeIndex * 2, iLeft, iMid, iIndex, iValue);
}
else
{
Modify(iTreeNodeIndex * 2 + 1, iMid + 1, iRight, iIndex, iValue);
}
m_vData[iTreeNodeIndex] = max(m_vData[iTreeNodeIndex * 2], m_vData[iTreeNodeIndex * 2 + 1]);
}
const int m_iArrSize;
std::vector m_vData;
};

class CMaxLineTreeMap
{
public:
CMaxLineTreeMap(int iArrSize) :m_iArrSize(iArrSize)
{

 }
 //iIndex 从0开始
 void Modify(int iIndex, int iValue)
 {
	 Modify(1, 1, m_iArrSize, iIndex + 1, iValue);
 }
 //iNeedQueryLeft iNeedQueryRight 从0开始
 int Query(const int iNeedQueryLeft, const int iNeedQueryRight)
 {
	 return Query(1, 1, m_iArrSize, iNeedQueryLeft + 1, iNeedQueryRight + 1);
 }

protected:
int Query(const int iTreeNodeIndex, const int iRecordLeft, const int iRecordRight, const int iNeedQueryLeft, const int iNeedQueryRight)
{
if ((iNeedQueryLeft <= iRecordLeft) && (iNeedQueryRight >= iRecordRight))
{
return m_mData[iTreeNodeIndex];
}
const int iMid = (iRecordLeft + iRecordRight) / 2;
int iRet = 0;
if (iNeedQueryLeft <= iMid)
{
iRet = Query(iTreeNodeIndex * 2, iRecordLeft, iMid, iNeedQueryLeft, iNeedQueryRight);
}
if (iNeedQueryRight > iMid)
{
iRet = max(iRet, Query(iTreeNodeIndex * 2 + 1, iMid + 1, iRecordRight, iNeedQueryLeft, iNeedQueryRight));
}
return iRet;
}
void Modify(int iTreeNodeIndex, int iLeft, int iRight, int iIndex, int iValue)
{
if (iLeft == iRight)
{
m_mData[iTreeNodeIndex] = max(m_mData[iTreeNodeIndex], iValue);
return;
}
const int iMid = (iLeft + iRight) / 2;
if (iIndex <= iMid)
{
Modify(iTreeNodeIndex * 2, iLeft, iMid, iIndex, iValue);
}
else
{
Modify(iTreeNodeIndex * 2 + 1, iMid + 1, iRight, iIndex, iValue);
}
m_mData[iTreeNodeIndex] = max(m_mData[iTreeNodeIndex * 2], m_mData[iTreeNodeIndex * 2 + 1]);
}
const int m_iArrSize;
std::unordered_map<int, int> m_mData;
};

template
class CSumLineTree
{
public:
CSumLineTree(int iEleSize) :m_iEleSize(iEleSize), m_vArr(m_iEleSize * 4), m_vChildAdd(m_iEleSize * 4)
{

 }
 void Add(int iLeftIndex, int iRightIndex, int iValue)
 {
	 Add(1, 1, m_iEleSize, iLeftIndex+1, iRightIndex+1, iValue);
 }
 T Query(int iLeftIndex, int iRightIndex)
 {
	 return Query(1, 1, m_iEleSize, iLeftIndex + 1, iRightIndex + 1);
 }

private:
T Query(int iNode, int iDataLeft, int iDataRight, int iOpeLeft, int iOpeRight)
{
if ((iOpeLeft <= iDataLeft) && (iOpeRight >= iDataRight))
{
return m_vArr[iNode];
}
Fresh(iNode, iDataLeft, iDataRight);
const int iMid = iDataLeft + (iDataRight - iDataLeft) / 2;
T ret(0);
if (iMid >= iOpeLeft)
{
ret += Query(iNode * 2, iDataLeft, iMid, iOpeLeft, iOpeRight);
}
if (iMid + 1 <= iOpeRight)
{
ret += Query(iNode * 2 + 1, iMid + 1, iDataRight, iOpeLeft, iOpeRight);
}
return ret;
}
/* 暴力解法
void Add(int iNode, int iDataLeft, int iDataRight, int iOpeLeft, int iOpeRight, int iValue)
{
m_vArr[iNode] += T(iValue)*(min(iDataRight, iOpeRight) - max(iDataLeft, iOpeLeft)+1);
if (iDataLeft == iDataRight)
{
return;
}
const int iMid = iDataLeft + (iDataRight - iDataLeft) / 2;
if (iMid >= iOpeLeft)
{
Add(iNode * 2, iDataLeft, iMid, iOpeLeft, iOpeRight, iValue);
}
if (iMid + 1 <= iOpeRight)
{
Add(iNode * 2 + 1, iMid + 1, iDataRight, iOpeLeft, iOpeRight, iValue);
}
}
/
void Fresh(int iNode, int iDataLeft, int iDataRight)
{
const int iMid = iDataLeft + (iDataRight - iDataLeft) / 2;
if (m_vChildAdd[iNode] != 0)
{
Add(iNode * 2, iDataLeft, iMid, iDataLeft, iMid, m_vChildAdd[iNode]);
Add(iNode * 2 + 1, iMid + 1, iDataRight, iMid + 1, iDataRight, m_vChildAdd[iNode]);
m_vChildAdd[iNode] = 0;
}
}
//懒惰法
void Add(int iNode, int iDataLeft, int iDataRight, int iOpeLeft, int iOpeRight, int iValue)
{
m_vArr[iNode] += T(iValue)
(min(iDataRight, iOpeRight) - max(iDataLeft, iOpeLeft) + 1);
if ((iOpeLeft <= iDataLeft) && (iOpeRight >= iDataRight))
{
m_vChildAdd[iNode] += T(iValue);
return;
}

	 Fresh(iNode,iDataLeft,iDataRight);
	 const int iMid = iDataLeft + (iDataRight - iDataLeft) / 2;
	 if (iMid >= iOpeLeft)
	 {
		 Add(iNode * 2, iDataLeft, iMid, iOpeLeft, iOpeRight, iValue);
	 }
	 if (iMid + 1 <= iOpeRight)
	 {
		 Add(iNode * 2 + 1, iMid + 1, iDataRight, iOpeLeft, iOpeRight, iValue);
	 }
 }

 const int m_iEleSize;
 vector<T> m_vArr;
 vector<int> m_vChildAdd;

};

template
class CTreeArr
{
public:
CTreeArr(int iSize) :m_vData(iSize+1)
{

 }
 void Add(int index, T value)
 {
	 index++;
	 while (index < m_vData.size())
	 {
		 m_vData[index] += value;
		 index += index&(-index);
	 }
 }
 T Sum(int index)
 {
	 index++;
	 T ret = 0;
	 while (index )
	 {
		 ret += m_vData[index];
		 index -= index&(-index);
	 }
	 return ret;
 }
 T Get(int index)
 {
	 return Sum(index) - Sum(index - 1);
 }

private:
vector m_vData;
};

//iCodeNum 必须大于等于可能的字符数
template
class CHashStr {
public:
CHashStr(string s, int iCodeNum, int iCodeBegin = 1, char chBegin = ‘a’) {
m_c = s.length();
m_vP.resize(m_c + 1);
m_vP[0] = 1;
m_vHash.resize(m_c + 1);
for (int i = 0; i < m_c; i++)
{
const int P = iCodeBegin + iCodeNum;
m_vHash[i + 1] = m_vHash[i] * P + s[i] - chBegin + iCodeBegin;
m_vP[i + 1] = m_vP[i] * P;
}
}
int GetHash(int left, int right)
{
return ( m_vHash[right + 1] - m_vHash[left] * m_vP[right - left + 1]).ToInt();
}
inline int GetHash(int right)
{
return m_vHash[right + 1].ToInt();
}
int m_c;
vector<C1097Int> m_vP;
vector<C1097Int> m_vHash;
};

template
class C2HashStr
{
public:
C2HashStr(string s) {
m_pHash1 = std::make_unique<CHashStr<>>(s, 26);
m_pHash2 = std::make_unique < CHashStr>(s, 27, 0);
}

 long long GetHash(int left, int right)
 {
	 return (long long)m_pHash1->GetHash(left, right)*(MOD2 + 1) + m_pHash2->GetHash(left, right);
 }
 long long GetHash( int right)
 {
	 return (long long)m_pHash1->GetHash( right)*(MOD2 + 1) + m_pHash2->GetHash( right);
 }

private:
std::unique_ptr<CHashStr<>> m_pHash1;
std::unique_ptr<CHashStr> m_pHash2;
};

template
class CDynaHashStr {
public:
CDynaHashStr(int iCodeNum, int iCodeBegin = 1, char chBegin = ‘a’) :m_iUnit(iCodeNum + iCodeBegin), m_iP(1), m_iBegin(iCodeBegin - chBegin)
{

 }
 inline void push_back(const char& ch)
 {
	const int iNum = ch + m_iBegin;
	m_iHash *= m_iUnit;
	m_iHash += iNum;
	m_iP *= m_iUnit;
 }
 inline void push_front(const char& ch)
 {
	 const int iNum = ch + m_iBegin;
	 m_iHash +=  m_iP*iNum;
	 m_iP *= m_iUnit;
 }
 inline int GetHash() const
 {
	 return m_iHash;
 }
 const int m_iUnit;
 const int m_iBegin;
 C1097Int<MOD> m_iHash;
 C1097Int<MOD> m_iP;

};

template
class C2DynaHashStr {
public:
C2DynaHashStr(int iCodeNum, int iCodeBegin = 1, char chBegin = ‘a’)
{
m_pHash1 = new CDynaHashStr<>(iCodeNum, iCodeBegin, chBegin);
m_pHash2 = new CDynaHashStr(iCodeNum, iCodeBegin, chBegin);
}
~C2DynaHashStr()
{
delete m_pHash1;
delete m_pHash2;
}
inline void push_back(const char& ch)
{
m_pHash1->push_back(ch);
m_pHash2->push_back(ch);
}
inline void push_front(const char& ch)
{
m_pHash1->push_front(ch);
m_pHash2->push_front(ch);
}
long long Hash()const
{
return (long long)MOD2m_pHash1->m_iHash.ToInt() + m_pHash2->m_iHash.ToInt();
}
bool operator==(const C2DynaHashStr& other) const
{
return (m_pHash1->m_iHash.ToInt() == other.m_pHash1->m_iHash.ToInt()) && (m_pHash2->m_iHash.ToInt() == other.m_pHash2->m_iHash.ToInt());
}
CDynaHashStr<>
m_pHash1;
CDynaHashStr* m_pHash2 ;
};
namespace NSort
{
template
bool SortVecVec(const vector& v1, const vector& v2)
{
return v1[ArrIndex] < v2[ArrIndex];
};
}

namespace NCmp
{
template
bool Less(const std::pair<Class1, int>& p, Class1 iData)
{
return p.first < iData;
}

 template<class Class1>
 bool  Greater(const std::pair<Class1, int>& p, Class1 iData)
 {
	 return p.first > iData;
 }

template<class _Ty1,class _Ty2>
class CLessPair
{
public:
	bool operator()(const std::pair<_Ty1, _Ty2>& p1, const std::pair<_Ty1, _Ty2>& p2)const
	{
		return p1.first < p2.first;
	}
};

template<class _Ty1, class _Ty2>
class CGreatePair
{
public:
	bool operator()(const std::pair<_Ty1, _Ty2>& p1, const std::pair<_Ty1, _Ty2>& p2)const
	{
		return p1.first > p2.first;
	}
};

}

class CIndexVector
{
public:
template
CIndexVector(vector& data)
{
for (int i = 0; i < data.size(); i++)
{
m_indexs.emplace_back(i);
}
std::sort(m_indexs.begin(), m_indexs.end(), [data](const int& i1, const int& i2)
{
return data[i1] < data[i2];
});
}
int GetIndex(int index)
{
return m_indexs[index];
}
private:
vector m_indexs;
};

class CMedian
{
public:
void AddNum(int iNum)
{
m_queTopMin.emplace(iNum);
MakeNumValid();
MakeSmallBig();
}
void Remove(int iNum)
{
if (m_queTopMax.size() && (iNum <= m_queTopMax.top()))
{
m_setTopMaxDel.insert(iNum);
}
else
{
m_setTopMinDel.insert(iNum);
}

	PopIsTopIsDel(m_queTopMin, m_setTopMinDel);
	PopIsTopIsDel(m_queTopMax, m_setTopMaxDel);
	MakeNumValid();
	MakeSmallBig();
}
double Median()
{
	const int iMaxNum = m_queTopMin.size() - m_setTopMinDel.size();
	const int iMinNum = m_queTopMax.size() - m_setTopMaxDel.size();
	if (iMaxNum > iMinNum)
	{
		return m_queTopMin.top();
	}
	return ((double)m_queTopMin.top() + m_queTopMax.top())/2.0;
}
template<class T>
void PopIsTopIsDel(T& que, std::unordered_multiset<int>& setTopMaxDel)
{
	while (que.size() && (setTopMaxDel.count(que.top())))
	{
		setTopMaxDel.erase(setTopMaxDel.find(que.top()));
		que.pop();
	}
}
void MakeNumValid()
{
	const int iMaxNum = m_queTopMin.size() - m_setTopMinDel.size();
	const int iMinNum = m_queTopMax.size() - m_setTopMaxDel.size();
	//确保两个队的数量
	if (iMaxNum > iMinNum + 1)
	{
		int tmp = m_queTopMin.top();
		m_queTopMin.pop();
		m_queTopMax.emplace(tmp);
		PopIsTopIsDel(m_queTopMin, m_setTopMinDel);
	}
	if (iMinNum > iMaxNum)
	{
		int tmp = m_queTopMax.top();
		m_queTopMax.pop();
		m_queTopMin.push(tmp);
		PopIsTopIsDel(m_queTopMax, m_setTopMaxDel);
	}
}
void MakeSmallBig()
{
	if (m_queTopMin.empty() || m_queTopMax.empty())
	{
		return;
	}
	while (m_queTopMin.top() < m_queTopMax.top())
	{
		const int iOldTopMin = m_queTopMin.top();
		const int iOldTopMax = m_queTopMax.top();
		m_queTopMin.pop();
		m_queTopMax.pop();
		m_queTopMin.emplace(iOldTopMax);
		m_queTopMax.emplace(iOldTopMin);
		PopIsTopIsDel(m_queTopMin, m_setTopMinDel);
		PopIsTopIsDel(m_queTopMax, m_setTopMaxDel);
	}
}
std::priority_queue<int> m_queTopMax;
std::priority_queue<int, vector<int>, greater<int>> m_queTopMin;
std::unordered_multiset<int> m_setTopMaxDel, m_setTopMinDel;

};

template
class CDistanceGrid
{
public:
CDistanceGrid(const vector<vector>& grid) :m_grid(grid), m_r(grid.size()), m_c(grid[0].size())
{

}
//单源路径 D 算法 ,时间复杂度:r*c*log(r*c)
inline int Dis(int r1, int c1, int r2, int c2)
{	
	vector<vector<int>> vDis(iMaxRow, vector<int>(iMaxCol, INT_MAX));

	auto Add = [&vDis, this](std::priority_queue<pair<int, int>, vector<std::pair<int, int>>, greater<pair<int, int>>>& queCur, int iDis, int r, int c)
	{
		const int iRowColMask = iMaxCol * r + c;
		if (iDis >= vDis[r][c])
		{
			return;
		}
		queCur.emplace(iDis,iRowColMask);
		vDis[r][c] = iDis;
	};
	auto Move = [&](std::priority_queue<pair<int, int>, vector<std::pair<int, int>>, greater<pair<int, int>>>& queCur, int iDis, int r, int c)
	{
		if ((r < 0) || (r >= m_r))
		{
			return;
		}
		if ((c < 0) || (c >= m_c))
		{
			return;
		}
		if (m_grid[r][c] < 1)
		{
			return;
		}
		Add(queCur,iDis, r, c);
	};

	std::priority_queue<pair<int, int>, vector<std::pair<int, int>>, greater<pair<int, int>>> que;		
	Add(que,0,r1, c1);
	while (que.size())
	{
		const int iDis = que.top().first;
		const int iStart = que.top().second;
		que.pop();
		const int r = iStart / iMaxCol;
		const int c = iStart % iMaxCol;
		if ((r == r2) && (c == c2))
		{
			return iDis;
		}
		if (iDis > vDis[r][c])
		{
			continue;
		}
		
		Move(que, iDis + 1, r + 1, c);
		Move(que, iDis + 1, r - 1, c);
		Move(que, iDis + 1, r, c + 1);
		Move(que, iDis + 1, r, c - 1);
	}

	return -1;
}

private:
virtual bool IsCanMoveStatue(int r, int c)
{
return m_grid[r][c] >= 1;
}
const int m_r;
const int m_c;
const vector<vector>& m_grid;

};

class CBFSGridDist
{
public:
CBFSGridDist(const vector<vector>& bCanVisit, int r, int c) :m_bCanVisit(bCanVisit), m_r(m_bCanVisit.size()), m_c(m_bCanVisit[0].size())
{
m_vDis.assign(m_r, vector(m_c,INT_MAX/2));
Dist(r, c);
}
bool Vilid(const int r,const int c )
{
if ((r < 0) || (r >= m_r))
{
return false;
}
if ((c < 0) || (c >= m_c))
{
return false;
}
return true;
}
const vector<vector>& Dis()const
{
return m_vDis;
}
const vector<vector>& m_bCanVisit;
private:
//INT_MAX/2 表示无法到达
void Dist(int r, int c)
{
m_vDis.assign(m_r, vector(m_c, INT_MAX / 2));
vector<vector> vHasDo(m_r, vector(m_c));
std::queue<std::pair<int, int>> que;
auto Add = [&](const int& r, const int& c, const int& iDis)
{
if (!Vilid(r, c))
{
return;
}
if (vHasDo[r][c])
{
return;
}
if (!m_bCanVisit[r][c])
{
vHasDo[r][c] = true;
return;
}
if (iDis >= m_vDis[r][c])
{
return;
}

		que.emplace(r, c);
		m_vDis[r][c] = iDis;
		vHasDo[r][c] = true;
	};
	Add(r, c, 0);
	while (que.size())
	{
		const int r = que.front().first;
		const int c = que.front().second;
		que.pop();
		const int iDis = m_vDis[r][c];
		Add(r + 1, c, iDis + 1);
		Add(r - 1, c, iDis + 1);
		Add(r, c + 1, iDis + 1);
		Add(r, c - 1, iDis + 1);
	}

}
vector<vector<int>> m_vDis;
const int m_r;
const int m_c;

};

class C2BNumTrieNode
{
public:
C2BNumTrieNode()
{
m_childs[0] = m_childs[1] = nullptr;
}
bool GetNot0Child(bool bFirstRight)
{
auto ptr = m_childs[bFirstRight];
if (ptr && (ptr->m_iNum >0))
{
return bFirstRight;
}
return !bFirstRight;
}
int m_iNum = 0;
C2BNumTrieNode* m_childs[2];
};

template
class C2BNumTrie
{
public:
C2BNumTrie()
{
m_pRoot = new C2BNumTrieNode();
}
void Add(int iNum)
{
m_setHas.emplace(iNum);
C2BNumTrieNode* p = m_pRoot;
for (int i = iLeveNum - 1; i >= 0; i–)
{
p->m_iNum++;
bool bRight = iNum & (1 << i);
if (nullptr == p->m_childs[bRight])
{
p->m_childs[bRight] = new C2BNumTrieNode();
}
p = p->m_childs[bRight];
}
p->m_iNum++;
}
void Del(int iNum)
{
auto it = m_setHas.find(iNum);
if (m_setHas.end() == it)
{
return;
}
m_setHas.erase(it);
C2BNumTrieNode* p = m_pRoot;
for (int i = iLeveNum - 1; i >= 0; i–)
{
p->m_iNum–;
bool bRight = iNum & (1 << i);
p = p->m_childs[bRight];
}
p->m_iNum–;
}
int MaxXor(int iNum)
{
C2BNumTrieNode* p = m_pRoot;
int iRet = 0;
for (int i = iLeveNum - 1; i >= 0; i–)
{
bool bRight = !(iNum & (1 << i));
bool bSel = p->GetNot0Child(bRight);
p = p->m_childs[bSel];
if (bSel == bRight)
{
iRet |= (1 << i);
}
}
return iRet;
}
C2BNumTrieNode* m_pRoot;
std::unordered_multiset m_setHas;
};

struct SValueItem
{
SValueItem()
{

}
SValueItem(int iValue)
{
	m_iCoefficient = iValue;
}
SValueItem operator*(const SValueItem& o)const
{
	SValueItem ret(m_iCoefficient*o.m_iCoefficient);
	int i = 0, j = 0;
	while ((i < m_vVars.size()) && (j < o.m_vVars.size()))
	{
		if (m_vVars[i] < o.m_vVars[j])
		{
			ret.m_vVars.emplace_back(m_vVars[i]);
			i++;
		}
		else
		{
			ret.m_vVars.emplace_back(o.m_vVars[j]);
			j++;
		}
	}
	ret.m_vVars.insert(ret.m_vVars.end(), m_vVars.begin()+i, m_vVars.end());
	ret.m_vVars.insert(ret.m_vVars.end(), o.m_vVars.begin()+j, o.m_vVars.end());
	return ret;
}
bool operator<(const SValueItem& o)const
{
	if (m_vVars.size() == o.m_vVars.size())
	{
		return m_vVars < o.m_vVars;
	}
	return m_vVars.size() > o.m_vVars.size();
}
vector<std::string> m_vVars;
int m_iCoefficient=1;//系数、倍率
std::string ToString()const
{
	std::ostringstream os;
	os << m_iCoefficient ;
	for (const auto&s : m_vVars)
	{
		os << "*" << s;
	}
	return os.str();
}

};

struct SValue
{
SValue()
{

}
SValue(int iValue)
{
	SValueItem item;
	item.m_iCoefficient = iValue;
	m_items.emplace(item);
}
SValue(std::string strName)
{
	SValueItem item;
	item.m_vVars.emplace_back(strName);
	m_items.emplace(item);
}
SValue operator-(const SValue& o)const
{
	SValue ret;
	ret.m_items = m_items;
	for (auto it : o.m_items)
	{
		ret -= it;
	}
	return ret;
}
SValue operator+(const SValue& o)const
{
	SValue ret;
	ret.m_items = m_items;
	for (auto it : o.m_items)
	{
		ret += it;
	}			
	return ret;
}
SValue operator*(const SValue& o)const
{
	SValue ret;
	for (const auto it : m_items)
	{
		for (const auto ij : o.m_items)
		{
			ret += it*ij;
		}
	}
	return ret;
}
SValue& operator+=(const SValueItem& item)
{
	auto it = m_items.find(item);
	if (m_items.end() == it)
	{
		m_items.emplace(item);
	}
	else
	{
		auto tmp = *it;
		tmp.m_iCoefficient += item.m_iCoefficient;
		m_items.erase(it);
		m_items.emplace(tmp);
	}
	return *this;
}
SValue& operator-=(const SValueItem& item)
{
	auto it = m_items.find(item);
	if (m_items.end() == it)
	{
		auto tmp = item;
		tmp.m_iCoefficient *= -1;
		m_items.emplace(tmp);
	}
	else
	{
		auto tmp = *it;
		tmp.m_iCoefficient -= item.m_iCoefficient;
		m_items.erase(it);
		m_items.emplace(tmp);
	}
	return *this;
}
vector<std::string> ToStrings()const
{
	vector<std::string> vRet;
	for (const auto& item : m_items)
	{
		if (0 == item.m_iCoefficient)
		{
			continue;
		}
		vRet.emplace_back(item.ToString());
	}
	return vRet;
}
std::set<SValueItem> m_items;

};

class CDelIndexs
{
public:
CDelIndexs()
{

}
CDelIndexs(int iSize)
{
	Init(iSize);
}
void Init(int iSize)
{
	m_bDels.assign(iSize, false);
	m_vNext.resize(iSize);
	for (int i = 0; i < iSize; i++)
	{
		m_vNext[i] = i + 1;
	}
}
void Del(int index)
{
	if ((index < 0) || (index >= m_vNext.size()))
	{
		return;
	}
	if (m_bDels[index])
	{
		return;
	}
	m_bDels[index] = true;

}
void SetCur(int index)
{
	if (index < 0)
	{
		m_iCur = m_vNext.size();
	}
	else
	{
		m_iCur = FreshCur(index);
	}
}
int NextIndex()
{
	if (m_iCur >= m_vNext.size())
	{
		return -1;
	}
	auto ret = m_iCur;
	SetCur(m_vNext[m_iCur]);
	return ret;
}

private:
int FreshCur(int index)
{
if (index >= m_vNext.size())
{
return m_vNext.size();
}
if (!m_bDels[index])
{
return index;
}

	return m_vNext[index] = FreshCur(m_vNext[index]);
}
int m_iCur = 0;
vector<bool> m_bDels;
vector<int> m_vNext;

};

class CUnionFind
{
public:
CUnionFind(int iSize) :m_vConnetNO(iSize), m_vConnectSize(iSize, 1)
{
for (int i = 0; i < iSize; i++)
{
m_vConnetNO[i] = i;
}
m_iConnetSize = iSize;
}
int GetConnectNO(int iNode)
{
int& iConnectNO = m_vConnetNO[iNode];
if (iNode == iConnectNO)
{
return iNode;
}
return iConnectNO = GetConnectNO(iConnectNO);
}
void Union(int iNode1, int iNode2)
{
const int iConnectNO1 = GetConnectNO(iNode1);
const int iConnectNO2 = GetConnectNO(iNode2);
if (iConnectNO1 == iConnectNO2)
{
return ;
}
m_iConnetSize–;
if (iConnectNO1 > iConnectNO2)
{
UnionConnect(iConnectNO1, iConnectNO2);
}
else
{
UnionConnect(iConnectNO2, iConnectNO1);
}
}
int GetAConnectSizeByNode(int iNode)
{
return m_vConnectSize[GetConnectNO(iNode)];
}
bool IsConnect(int iNode1, int iNode2)
{
return GetConnectNO(iNode1) == GetConnectNO(iNode2);
}
int ConnetSize()const
{
return m_iConnetSize;
}
private:
void UnionConnect(int iFrom, int iTo)
{
m_vConnectSize[iTo] += m_vConnectSize[iFrom];
m_vConnetNO[iFrom] = iTo;
}
vector m_vConnetNO;//各点所在联通区域的编号,本联通区域任意一点的索引,为了增加可理解性,用最小索引
vector m_vConnectSize;//各联通区域点数量
int m_iConnetSize;
};

class CUnionFindMST
{
public:
CUnionFindMST(const int iNodeSize) :m_uf(iNodeSize)
{

}
void AddEdge(const int iNode1, const int iNode2, int iWeight)
{
	if (m_uf.IsConnect(iNode1, iNode2))
	{
		return;
	}
	m_iMST += iWeight;
	m_uf.Union(iNode1, iNode2);
}
void AddEdge(const vector<int>& v )
{
	AddEdge(v[0], v[1], v[2]);
}
int MST()
{
	if (m_uf.ConnetSize() > 1)
	{
		return -1;
	}
	return m_iMST;
}

private:
int m_iMST = 0;
CUnionFind m_uf;
};

class CNearestMST
{
public:
CNearestMST(const int iNodeSize) :m_bDo(iNodeSize), m_vDis(iNodeSize, INT_MAX), m_vNeiTable(iNodeSize)
{

}
void Init(const vector<vector<int>>& edges)
{
	for (const auto& v : edges)
	{
		Add(v);
	}
}
void Add(const vector<int>& v )
{
	m_vNeiTable[v[0]].emplace_back(v[1], v[2]);
	m_vNeiTable[v[1]].emplace_back(v[0], v[2]);
}
int MST(int start)
{
	int next = start;
	while ((next = AddNode(next)) >= 0);
	return m_iMST;
}
int MST(int iNode1, int iNode2,int iWeight)
{
	m_bDo[iNode1] = true;
	for (const auto& it : m_vNeiTable[iNode1])
	{
		if (m_bDo[it.first])
		{
			continue;
		}
		m_vDis[it.first] = min(m_vDis[it.first],(long long) it.second);
	}
	m_iMST = iWeight;

	int next = iNode2;
	while ((next = AddNode(next)) >= 0);
	return m_iMST;
}

private:
int AddNode(int iCur)
{
m_bDo[iCur] = true;
for (const auto& it : m_vNeiTable[iCur])
{
if (m_bDo[it.first])
{
continue;
}
m_vDis[it.first] = min(m_vDis[it.first], (long long)it.second);
}

	int iMinIndex = -1;
	for (int i = 0; i < m_vDis.size(); i++)
	{
		if (m_bDo[i])
		{
			continue;
		}
		if ((-1 == iMinIndex) || (m_vDis[i] < m_vDis[iMinIndex]))
		{
			iMinIndex =i;		
		}
	}
	if ( -1 != iMinIndex)
	{
		if (INT_MAX == m_vDis[iMinIndex])
		{
			m_iMST = -1;
			return -1;
		}
		m_iMST += m_vDis[iMinIndex];
	}
	
	return iMinIndex;
}
vector<bool> m_bDo;
vector<long long> m_vDis;
vector < vector<std::pair<int, int>>> m_vNeiTable;
long long m_iMST = 0;

};

typedef pair<long long,int> PAIRLLI;
class CDis
{
public:
static void Dis(vector& vDis, int start, const vector<vector<pair<int, int>>>& vNeiB)
{
std::priority_queue<PAIRLLI, vector, greater> minHeap;
minHeap.emplace(0, start);
while (minHeap.size())
{
const long long llDist = minHeap.top().first;
const int iCur = minHeap.top().second;
minHeap.pop();
if (-1 != vDis[iCur])
{
continue;
}
vDis[iCur] = llDist;
for (const auto& it : vNeiB[iCur])
{
minHeap.emplace(llDist + it.second, it.first);
}
}

}

};

class CNearestDis
{
public:
CNearestDis(int iSize) :m_iSize(iSize), DIS(m_vDis), PRE(m_vPre)
{

}
void Cal(int start, const vector<vector<pair<int, int>>>& vNeiB)
{
	m_vDis.assign(m_iSize, -1);
	m_vPre.assign(m_iSize, -1);
	vector<bool> vDo(m_iSize);//点是否已处理
	auto AddNode = [&](int iNode)
	{
		//const int iPreNode = m_vPre[iNode];
		long long llPreDis = m_vDis[iNode];

		vDo[iNode] = true;
		for (const auto& it : vNeiB[iNode])
		{
			if (vDo[it.first])
			{
				continue;
			}

			if ((-1 == m_vDis[it.first]) || (it.second + llPreDis < m_vDis[it.first]))
			{
				m_vDis[it.first] = it.second + llPreDis;
				m_vPre[it.first] = iNode;
			}				
		}

		long long llMinDis = LLONG_MAX;
		int iMinIndex = -1;
		for (int i = 0; i < m_vDis.size(); i++)
		{
			if (vDo[i])
			{
				continue;
			}
			if (-1 == m_vDis[i])
			{
				continue;
			}
			if (m_vDis[i] < llMinDis)
			{
				iMinIndex = i;
				llMinDis = m_vDis[i];
			}
		}
		return (LLONG_MAX == llMinDis) ? -1 : iMinIndex;
	};

	int next = start;
	m_vDis[start] = 0;
	while (-1 != (next= AddNode(next)));
}
void Cal(const int start, vector<vector<int>>& edges)
{
	vector<vector<pair<int, int>>> vNeiB(m_iSize);
	for (int i = 0; i < edges.size(); i++)
	{
		const auto& v = edges[i];
		vNeiB[v[0]].emplace_back(v[1], v[2]);
		vNeiB[v[1]].emplace_back(v[0], v[2]);
	}
	Cal(start, vNeiB);
}
const vector<long long>& DIS;
const vector<int>& PRE;

private:
const int m_iSize;
vector m_vDis;//各点到起点的最短距离
vector m_vPre;//最短路径的前一点
};

class CNeiBo2
{
public:
CNeiBo2(int n, vector<vector>& edges, bool bDirect)
{
m_vNeiB.resize(n);
for (const auto& v : edges)
{
m_vNeiB[v[0]].emplace_back(v[1]);
if (!bDirect)
{
m_vNeiB[v[1]].emplace_back(v[0]);
}
}
}
vector<vector> m_vNeiB;
};

struct SDecimal
{
SDecimal(int iNum=0, int iDeno = 1)
{
m_iNum = iNum;
m_iDeno = iDeno;
int iGCD = GCD(abs(m_iNum), abs(m_iDeno));
m_iNum /= iGCD;
m_iDeno /= iGCD;
if (m_iDeno < 0)
{
m_iDeno = -m_iDeno;
m_iNum = -m_iNum;
}
}
SDecimal operator*(const SDecimal& o)const
{
return SDecimal(m_iNumo.m_iNum, m_iDenoo.m_iDeno);
}
SDecimal operator/(const SDecimal& o)const
{
return SDecimal(m_iNumo.m_iDeno, m_iDenoo.m_iNum);
}
SDecimal operator+(const SDecimal& o)const
{
const int iGCD = GCD(m_iDeno, o.m_iDeno);
const int iDeno = m_iDenoo.m_iDeno / iGCD;
return SDecimal(m_iNum
(iDeno / m_iDeno) + o.m_iNum*(iDeno / o.m_iDeno), iDeno);
}
SDecimal operator-(const SDecimal& o)const
{
const int iGCD = GCD(m_iDeno, o.m_iDeno);
const int iDeno = m_iDenoo.m_iDeno / iGCD;
return SDecimal(m_iNum
(iDeno / m_iDeno) - o.m_iNum*(iDeno / o.m_iDeno), iDeno);
}
bool operator==(const SDecimal& o)const
{
return (m_iNum == o.m_iNum) && (m_iDeno == o.m_iDeno);
}
bool operator<(const SDecimal& o)const
{
auto tmp = *this - o;
return tmp.m_iNum < 0;
}
int m_iNum=0;//分子
int m_iDeno=1;//分母
};

struct point{
double x, y;
point(double i, double j) :x(i), y(j){}
};

//算两点距离
double dist(double x1, double y1, double x2, double y2){
return sqrt((x1 - x2)(x1 - x2) + (y1 - y2)(y1 - y2));
}

//计算圆心
point CircleCenter(point& a, point& b, int r){
//算中点
point mid((a.x + b.x) / 2.0, (a.y + b.y) / 2.0);
//AB距离的一半
double d = dist(a.x, a.y, mid.x, mid.y);
//计算h
double h = sqrt(rr - dd);
//计算垂线
point ba(b.x - a.x, b.y - a.y);
point hd(-ba.y, ba.x);
double len = sqrt(hd.xhd.x + hd.yhd.y);
hd.x /= len, hd.y /= len;
hd.x *= h, hd.y *= h;
return point(hd.x + mid.x, hd.y + mid.y);
}

class C01LineTree
{
public:
C01LineTree(const vector& nums) :m_iEleSize(nums.size())
{
m_arr.resize(m_iEleSize * 4);
Init(nums,1, 1, m_iEleSize);
m_vNeedFreshChilds.assign(m_iEleSize * 4, false);
}
void Rotato(int iLeftZeroIndex,int iRightZeroIndex )
{
int iRotatoLeft = iLeftZeroIndex + 1;
int iRotatoRight = iRightZeroIndex + 1;
Rotato(1, 1, m_iEleSize, iRotatoLeft, iRotatoRight);
}
int Query()
{
return m_arr[1];
}
private:
void Rotato(int iSaveIndex, int iDataBegin, int iDataEnd, int iRotatoLeft, int iRotatoRight)
{
if ((iRotatoLeft <= iDataBegin) && (iRotatoRight >= iDataEnd))
{//整个范围需要更新
RotatoSelf(iSaveIndex, iDataBegin, iDataEnd);
return;
}

	int iMid = iDataBegin + (iDataEnd - iDataBegin) / 2;
	if (m_vNeedFreshChilds[iSaveIndex])
	{
		RotatoSelf(iSaveIndex * 2, iDataBegin, iMid);
		RotatoSelf(iSaveIndex * 2 + 1, iMid + 1, iDataEnd);
		m_vNeedFreshChilds[iSaveIndex] = false;
	}	
	if (iMid >= iRotatoLeft)
	{
		Rotato(iSaveIndex * 2, iDataBegin, iMid, iRotatoLeft, iRotatoRight);
	}
	if (iMid + 1 <= iRotatoRight)
	{
		Rotato(iSaveIndex * 2 + 1, iMid + 1, iDataEnd, iRotatoLeft, iRotatoRight);
	}
	m_arr[iSaveIndex] = m_arr[iSaveIndex * 2] + m_arr[iSaveIndex * 2 + 1];
}
void RotatoSelf(int iSaveIndex, int iDataBegin, int iDataEnd)
{
	//总数量 - 翻转后0(翻转前1)的数量
	m_arr[iSaveIndex] = (iDataEnd - iDataBegin + 1) - m_arr[iSaveIndex];
	//懒惰法,标记本节点的子孙节点没更新
	m_vNeedFreshChilds[iSaveIndex] = !m_vNeedFreshChilds[iSaveIndex];
}
void Init(const vector<int>& nums, int iSaveIndex,int iDataBegin, int iDataEnd)
{
	if (iDataBegin == iDataEnd)
	{
		m_arr[iSaveIndex] = nums[iDataBegin - 1];
		return;
	}
	int iMid = iDataBegin + (iDataEnd - iDataBegin) / 2;
	Init(nums, iSaveIndex * 2  , iDataBegin, iMid);
	Init(nums, iSaveIndex * 2 + 1, iMid + 1, iDataEnd);
	m_arr[iSaveIndex] = m_arr[iSaveIndex * 2] + m_arr[iSaveIndex * 2 + 1];
}
const int m_iEleSize;
vector<int> m_arr;
vector<bool> m_vNeedFreshChilds;

};

/*
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
TreeNode(int x, int iLeft) : val(x), left(new TreeNode(iLeft)), right(nullptr) {}
TreeNode(int x, int iLeft, int iRghit) : val(x), left(new TreeNode(iLeft)), right(new TreeNode(iRghit)) {}
};

namespace NTree
{
TreeNode* Init(const vector& nums, int iNull = 10000)
{
if (0 == nums.size())
{
return nullptr;
}
vector<TreeNode*> ptrs(nums.size() + 1), ptrParent(1);
for (int i = 0; i < nums.size(); i++)
{
if (iNull == nums[i])
{
continue;
}
const int iNO = i + 1;
ptrs[iNO] = new TreeNode(nums[i]);
ptrParent.emplace_back(ptrs[iNO]);
if (1 == iNO)
{
continue;
}
if (iNO & 1)
{//奇数是右支
ptrParent[iNO / 2]->right = ptrs[iNO];
}
else
{
ptrParent[iNO / 2]->left = ptrs[iNO];
}
}
return ptrs[1];
}
}
*/

class Solution {
public:
int kInversePairs(int n, int k) {
//n为1时,只有一种情况:逆序0
vector<C1097Int<>> pre = { C1097Int<>(1) };
for (int i = 2; i <= n; i++)
{
const int iNewLen = min(k + 1, (int)pre.size() + i);
vector<C1097Int<>> dp(iNewLen);
C1097Int<> iSum = 0;
for (int j = 0; j < iNewLen; j++)
{
if (j < pre.size())
{
iSum += pre[j];
}
const int iDelIndex = j - i;
if (iDelIndex >= 0)
{
iSum -= pre[iDelIndex];
}
dp[j] = iSum;
}
pre.swap(dp);
}
return (k < pre.size()) ? pre[k].ToInt() : 0;
}
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 **C+

+17**
如无特殊说明,本算法用**C++**实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/326479.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【架构】docker实现集群主从扩容【案例3/4】

实现集群主从扩容 当整个集群扛不住流量的情况时&#xff0c;需要给集群扩容增加设备&#xff0c;由3主3从&#xff0c;扩为4主4从。实现&#xff1a; 示意图如下&#xff1a; 第一步&#xff1a;新创建两个节点&#xff08;redis-node-7&#xff0c;端口6387和 redis-node…

「云渲染科普」3dmax vray动画渲染参数如何设置

动画渲染一直都是占用时间最多的地方&#xff0c;动画帧数通常 1 秒在 25 帧或者以上&#xff0c;电脑通常需要对每一帧的画面分批渲染&#xff0c;通常本地电脑由于配置上的限制&#xff0c;往往无法在短时间内快速的完成渲染任务。这时“云渲染”则成为了动画渲染的主要方案&…

USB Cable导致连接识别不良

2根USB线&#xff0c;连接USB2RS232芯片&#xff0c;有根线能够识别&#xff0c;另外一根不能识别。 好的线识别如下&#xff1a; 另外一根就不能识别

josef 约瑟抗干扰中间继电器 UEG/F-4H 四常开 导轨安装

系列型号 UEG/F-2H2D抗干扰中间继电器;UEG/F-1H1D抗干扰中间继电器; UEG/F-10H-L抗干扰中间继电器;UEG/F-10H-L2抗干扰中间继电器; UEG/F-10HS抗干扰中间继电器;UEG/F-2DPDT抗干扰中间继电器; UEG/F-4DPDT抗干扰中间继电器;UEG/F-8DPDT抗干扰中间继电器; UEG/F-2H抗干扰中间继…

(六)深入理解Bluez协议栈之“GATT Client Profile”

前言: 本章节我们继续介绍GATT Client Profile的实现,参考的程序是tools\btgatt-client.c,需要注意的一点,在./configure时,需要添加 --enable-test --enable-testing才会编译该c文件,编译完成后,生成的可执行程序为btgatt-client。本文主要以btgatt-client运行时可能会…

【Python数据可视化】matplotlib之绘制常用图形:折线图、柱状图(条形图)、饼图和直方图

文章传送门 Python 数据可视化matplotlib之绘制常用图形&#xff1a;折线图、柱状图&#xff08;条形图&#xff09;、饼图和直方图matplotlib之设置坐标&#xff1a;添加坐标轴名字、设置坐标范围、设置主次刻度、坐标轴文字旋转并标出坐标值matplotlib之增加图形内容&#x…

Angular系列教程之管道

文章目录 管道的基本概念使用内置管道创建自定义管道总结 在Angular中&#xff0c;管道&#xff08;Pipe&#xff09;是一个非常重要的概念。它们允许我们对数据进行转换、格式化和显示&#xff0c;并且可以轻松地在模板中使用。本篇文章将介绍Angular中的管道概念&#xff0c;…

golang文件相对路径问题

目录结构 2.具体代码&#xff1a; const dataFile "../data/data.json"_, fileName, _, _ : runtime.Caller(1)dataPath : path.Join(path.Dir(fileName), dataFile)fmt.Println(dataPath)// open filefile, err : os.Open(dataPath)if err ! nil {log.Fatalln(err…

AI扩展手写数字识别应用(二)

理解代码 输入处理 在新应用的代码部分&#xff0c;和我们在手写数字识别课程介绍的代码比起来&#xff0c;差别最大的地方就在于如何处理输入。在上个案例中&#xff0c;我们只需要简单地将正方形区域中的图像格式调整一下&#xff0c;即可用作MNIST模型的输入。而在本文的案…

【运维】安装双系统之后,如何删除主硬盘的Linux的引导,图文教程

前置条件&#xff1a;已经安装了windows10系统和Linux系统&#xff0c;而且windows10系统是C盘主要盘&#xff0c;Linux系统是安装在别的硬盘上&#xff0c;这个时候C盘主要盘里面的引导分区里是由Linux的引导的&#xff0c;所以打开电脑之后才能让你选是使用windows系统还是使…

一文了解Spring线程池(超详细+干货满满)

Spring默认线程池 simpleAsyncTaskExecutor Spring异步线程池的接口类是TaskExecutor &#xff0c;本质还是 java.util.concurrent.Executor&#xff0c;没有配置的情况下&#xff0c;默认使用的是 simpleAsyncTaskExecutor Component EnableAsync public class ScheduleTask…

josef约瑟 漏电继电器 LLJ-400F Φ100 分体式结构,导轨安装

LLJ-400F AC660V漏电继电器是一种检测线路触&#xff08;漏&#xff09;电&#xff0c;并发出一个机械开闭信号至控制电路装置。它可与各种规格的低压断路器或交流接触器组成组合式剩余电流动作保护器。在如今已实现了较为完善的农村低压电网分级&#xff08;二级或三级&#x…

Linux-->进程概念

文章目录 进程进程概念操作系统管理进程描述进程-PCB组织进程task_strcut 查看Linux下进程信息通过系统文件查看通过命令查看 通过系统调用获取进程标示符通过系统调用frok创建进程fork的使用进程状态运行阻塞挂起Linux下具体的进程状态 前台进程和后台进程kill僵尸进程孤儿进程…

两个方法实现echarts散点图的高光圆点

一、效果图&#xff1a; 二、代码 方法一&#xff1a;通过series的itemStyle进行设置&#xff0c;type为scatter 在 ECharts 中&#xff0c;要在二维散点图上实现看似 3D 的高光圆点效果&#xff0c;可以通过自定义散点图的 itemStyle 属性来实现。虽然无法直接创建真正的 3D…

【备战蓝桥杯】Python 内置模块datetime的介绍和应用

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-0TPX3guDWuSzAs1X {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

架构篇02-架构设计的历史背景

文章目录 机器语言&#xff08;1940 年之前&#xff09;汇编语言&#xff08;20 世纪 40 年代&#xff09;高级语言&#xff08;20 世纪 50 年代&#xff09;第一次软件危机与结构化程序设计&#xff08;20 世纪 60 年代~20 世纪 70 年代&#xff09;第二次软件危机与面向对象&…

设计模式——一文即可

对常用设计模式的总结&#xff0c;也是对设计模式专栏的总结 简单工厂模式 简单工厂模式&#xff08;Simple Factory Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一种创建对象的最佳方式&#xff0c;通过将对象的创建逻辑封装在一个工厂类中&#xff0c;客…

设备树下Led驱动实验-向设备树文件添加Led设备节点

一. 简介 前面简单学习了设备树文件的内容&#xff0c;语法&#xff0c;以及如何向设备树文件中添加设备节点信息。学习了驱动开发时&#xff0c;会使用到的设备树常用OF操作函数。本文我们就开始第一个基于设备树的 Linux 驱动实验-LED驱动实现。 本文具体学习在设备树文件添…

MES管理系统解决方案在汽配企业质量控制中的作用

在当今高度自动化的制造业环境中&#xff0c;质量控制已成为确保产品高品质的关键。特别是在汽配企业&#xff0c;产品通常由多个部件组装而成&#xff0c;且这些部件可能来自不同的供应商。这种复杂的生产模式带来了一个挑战&#xff1a;如何确保每一次生产操作都是正确的&…