我有 2 数组,$user = User::with([
'products' => function ($query) use ($date, $order) {
$query->where(function ($q) use ($date, $order) {
$q->where('created_at', $date); //This can accept more where() condition
})->orderBy($order,'DESC');
}])->get();
( 1 已编入索引)和before[N+1]
(after[]
的子数组)。现在,对于 M 查询,我需要查找before[]
中after[]
对于给定范围before[]
有多少元素。
例如:
N = 5
之前:(2,1,3,4,5)
之后:(1,3,4,5)
M = 2
在[1]之前和[5]之前,在[]之后存在L = 1,R = 5→4个元素(1,3,4,5)
在[2]之前和[4]之前,[]之后存在L = 2,R = 4→3元素(1,3,4)
我正在尝试使用MO的算法来找到它。以下是我的代码:
l,r
现在问题是我无法弄清楚如何定义using namespace std;
int N, Q;
// Variables, that hold current "state" of computation
long long current_answer;
long long cnt[100500];
// Array to store answers (because the order we achieve them is messed up)
long long answers[100500];
int BLOCK_SIZE;
// We will represent each query as three numbers: L, R, idx. Idx is
// the position (in original order) of this query.
pair< pair<int, int>, int> queries[100500];
// Essential part of Mo's algorithm: comparator, which we will
// use with std::sort. It is a function, which must return True
// if query x must come earlier than query y, and False otherwise.
inline bool mo_cmp(const pair< pair<int, int>, int> &x,
const pair< pair<int, int>, int> &y)
{
int block_x = x.first.first / BLOCK_SIZE;
int block_y = y.first.first / BLOCK_SIZE;
if(block_x != block_y)
return block_x < block_y;
return x.first.second < y.first.second;
}
// When adding a number, we first nullify it's effect on current
// answer, then update cnt array, then account for it's effect again.
inline void add(int x)
{
current_answer -= cnt[x] * cnt[x] * x;
cnt[x]++;
current_answer += cnt[x] * cnt[x] * x;
}
// Removing is much like adding.
inline void remove(int x)
{
current_answer -= cnt[x] * cnt[x] * x;
cnt[x]--;
current_answer += cnt[x] * cnt[x] * x;
}
int main()
{
cin.sync_with_stdio(false);
cin >> N >> Q; // Q- number of queries
BLOCK_SIZE = static_cast<int>(sqrt(N));
long long int before[N+1]; // 1 indexed
long long int after[] // subarray
// Read input queries, which are 0-indexed. Store each query's
// original position. We will use it when printing answer.
for(long long int i = 0; i < Q; i++) {
cin >> queries[i].first.first >> queries[i].first.second;
queries[i].second = i;
}
// Sort queries using Mo's special comparator we defined.
sort(queries, queries + Q, mo_cmp);
// Set up current segment [mo_left, mo_right].
int mo_left = 0, mo_right = -1;
for(long long int i = 0; i < Q; i++) {
// [left, right] is what query we must answer now.
int left = queries[i].first.first;
int right = queries[i].first.second;
// Usual part of applying Mo's algorithm: moving mo_left
// and mo_right.
while(mo_right < right) {
mo_right++;
add(after[mo_right]);
}
while(mo_right > right) {
remove(after[mo_right]);
mo_right--;
}
while(mo_left < left) {
remove(after[mo_left]);
mo_left++;
}
while(mo_left > left) {
mo_left--;
add(after[mo_left]);
}
// Store the answer into required position.
answers[queries[i].second] = current_answer;
}
// We output answers *after* we process all queries.
for(long long int i = 0; i < Q; i++)
cout << answers[i] << "\n";
和add function
。
有人可以帮我解决这些问题吗?
答案 0 :(得分:0)
注意:我将给定的数组表示为a
和b
。
让我们学习如何添加一个新位置(向右移动一个)。如果a[r]
已经存在,您可以忽略它。否则,我们需要添加a[r]
并在b[r]
中将a
的出现次数添加到答案中。最后,如果b[r]
已经在a
,我们需要在答案中添加一个。请注意,我们需要对数组进行两次计数:一个用于第一个数组,另一个用于第二个数组。
我们知道如何在O(1)
中添加一个位置,因此我们几乎就在那里。我们如何处理删除?
我们假设我们要删除子段。我们可以轻松修改计数数组。但是我们如何恢复答案呢?好吧,我们不是。你的解决方案是这样的:
那就是它。当我们将左指针移动到下一个块时,它需要重建结构,但在最坏的情况下仍需要O(N sqrt(N))
时间。
注意:当我们移除一个位置时,可能会使用count数组直接重新计算答案,但我上面展示的方式看起来也更容易。