问题描述
- 题目来源:CCF-CSP-201709-5:除法
解题思路
看题目,开始以为是考察线段树
。但是仔细思考之后发现,根据区间的操作“所有v的倍数除以v
”无法对现有的区间状态“和(Sum)”进行更新。因此线段树的LazyTag和区间状态都失效了。
改用树状数组
做,对每个点进行更新。根据数据量,可能会超时。试了一下,果不其然TLE。
没有了思路,参考ccf 201709-5 除法,对上述树状数组进行了两点的优化,就不超时了。
只能说,这题的数据有点玄学。
AC代码
#include <iostream>
using namespace std;
constexpr auto MaxSize = 100010;
using LL = long long int;
int NumSet[MaxSize] = { 0 };
LL BinaryIndexedTree[MaxSize] = { 0 };
inline int Lowbit(int x) { return x & (-x); }
LL GetSum(int Index)
{
LL Sum = 0;
while (Index > 0)
{
Sum += BinaryIndexedTree[Index];
Index -= Lowbit(Index);
}
return Sum;
}
void Update(int Index, int N, int Num)
{
while (Index <= N)
{
BinaryIndexedTree[Index] += Num;
Index += Lowbit(Index);
}
}
void Update(int Left,int Right, int N, int Divisor)
{
for (int Index = Left; Index <= Right; ++Index)
{
//玄学优化1
if (NumSet[Index] >= Divisor && NumSet[Index] % Divisor == 0)
{
int Lose = NumSet[Index] - NumSet[Index] / Divisor;
NumSet[Index] -= Lose;
Update(Index, N, -Lose);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
int N, OPNum;
cin >> N >> OPNum;
for (int i = 1; i <= N; ++i)
{
cin >> NumSet[i];
Update(i, N, NumSet[i]);
}
for (int i = 0; i < OPNum; ++i)
{
int OPCode, Left, Right, Divisior;
cin >> OPCode >> Left >> Right;
if (OPCode == 1)
{
cin >> Divisior;
if (Divisior == 1) continue; //玄学优化2
Update(Left, Right, N, Divisior);
}
else
{
cout << GetSum(Right) - GetSum(Left - 1) << endl;
}
}
return 0;
}