CF1060G
题意
数轴上初始时每个整点 \(x\) 有一个标号为 \(x\) 的球。有 \(n\) 个洞,在 \(a_1,\ a_2,\ ...,\ a_n\) 上。每一时刻位于洞上的球掉落,其余球左移到第一个没有球的整点上。
\(q\) 次询问,问 \(k_i\) 步后 \(x_i\) 上的球标号为多少。
\(1\ \leq\ n,\ q\ \leq\ 10^5,\ a_i,\ k_i,\ x_i\ \leq\ 10^9,\ a_i\) 互不相同。
做法1
令 \(X\ =\ 10^{15}\),我们考虑 \([X,\ X\ +\ n)\) 中的球的动向,可以发现这些球一定会遍历过所有 \([a_1,\ X\ +\ n)\) 的位置。如果我们可以维护每一时刻 \(t\) 这些球的位置,则可以将询问变为初始为 \(X\ +\ i\) 的球 move \(s\) 轮后位置在哪。
考虑如何快速维护球的位置。可以发现每时每刻这些球都会占据着 \([l,\ r]\) 中的所有位置。若 \([l,\ r]\) 中无坑,则坐标直接整体 \(-\ x\)。否则先删除掉掉入坑中的球,将剩余的球每一段都向前 move 即可。可以用线段树维护。注意删除第 \(i\) 个位置的时候要从后向前删,或者记录下之前已经删掉了多少个球。
时间复杂度 \(O((n\ +\ q)\ log\ n)\)
代码
#include <bits/stdc++.h>
#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif
using namespace std;
const long long oo = 1e15;
struct node {
node *ch[2];
int siz; long long tag, x;
node() : siz(1), tag(0) { memset(ch, 0, sizeof ch); }
void pull() { siz = ch[0]->siz + ch[1]->siz; return; }
void push() {
if(tag) {
for (int i = 0; i < 2; ++i) ch[i]->tag += tag, ch[i]->x += tag;
tag = 0;
}
return;
}
};
struct segment_tree {
int n;
node *root;
segment_tree() {}
segment_tree(vector<long long> &a) {
n = a.size();
function<void(node* &, int , int)> B = [&](node* &u, int l, int r) {
u = new node;
if(l == r) { u->x = a[l]; return; }
int mid = l + r >> 1;
return B(u->ch[0], l, mid), B(u->ch[1], mid + 1, r), u->pull();
};
B(root, 0, n - 1);
return;
}
void M(int a, int b, long long x) {
if(a <= b) M(a, b, x, root, 0, n - 1);
return;
}
void D(int i) { return D(i, root, 0, n - 1); }
int Qi(int k) { return Qi(k, root, 0, n - 1); }
long long Qx(int i) { return Qx(i, root, 0, n - 1); }
private:
void M(int a, int b, long long x, node* &u, int l, int r) {
if(a <= l && r <= b) { u->tag += x; u->x += x; return; }
int mid = l + r >> 1; u->push();
if(a <= mid) M(a, b, x, u->ch[0], l, mid);
if(mid < b) M(a, b, x, u->ch[1], mid + 1, r);
return u->pull();
}
void D(int i, node* &u, int l, int r) {
if(l == r) { assert(u->siz); u->x = -1; u->siz = 0; return; }
int mid = l + r >> 1; u->push();
if(i <= mid) D(i, u->ch[0], l, mid);
else D(i, u->ch[1], mid + 1, r);
return u->pull();
}
int Qi(int k, node* &u, int l, int r) {
if(l == r) return l;
int mid = l + r >> 1; u->push();
return (u->ch[0]->siz >= k) ? Qi(k, u->ch[0], l, mid) : Qi(k - u->ch[0]->siz, u->ch[1], mid + 1, r);
}
long long Qx(int i, node* &u, int l, int r) {
if(l == r) return u->x;
int mid = l + r >> 1; u->push();
return i <= mid ? Qx(i, u->ch[0], l, mid) : Qx(i, u->ch[1], mid + 1, r);
}
};
int main() {
ios::sync_with_stdio(false);
int n, m; cin >> n >> m;
vector<int> a(n); vector<long long> b(n);
for (int i = 0; i < n; ++i) cin >> a[i], b[i] = oo + i;
segment_tree seg(b);
long long t = 0;
vector<long long> ans(m); vector<pair<pair<int, int>, int> > q1(m); vector<pair<pair<long long, int>, int> > q2;
for (int i = 0; i < m; ++i) cin >> q1[i].first.first >> q1[i].first.second, q1[i].second = i;
for (int i = 0; i < q1.size(); ) {
if(q1[i].first.first < a[0] || q1[i].first.second == 0) ans[q1[i].second] = q1[i].first.first, swap(q1[i], q1.back()), q1.pop_back();
else ++i;
}
sort(q1.begin(), q1.end());
while(q1.size()) {
long long l = seg.Qx(seg.Qi(1)), r = seg.Qx(seg.Qi(seg.root->siz));
while(q1.size() && q1.back().first.first >= l && q1.back().first.first <= r) {
q2.push_back(make_pair(make_pair(t - q1.back().first.second, seg.Qi(q1.back().first.first - l + 1)), q1.back().second));
q1.pop_back();
}
if(!q1.size()) break;
++t;
int i = lower_bound(a.begin(), a.end(), l) - a.begin() - 1, j;
long long lst = l - 1;
for (j = i + 1; j < a.size(); ++j) {
if(a[j] > r) break;
if(lst + 1 < a[j]) seg.M(seg.Qi(lst + 1 - l + 1), seg.Qi(a[j] - 1 - l + 1), -j);
lst = a[j];
}
if(lst + 1 <= r) seg.M(seg.Qi(lst + 1 - l + 1), seg.Qi(r - l + 1), -j);
for (int fuck = 0, j = i + 1; j < a.size(); ++j) {
if(a[j] > r) break;
seg.D(seg.Qi(a[j] - l + 1 - fuck));
++fuck;
}
l = seg.Qx(seg.Qi(1)), r = seg.Qx(seg.Qi(seg.root->siz));
i = lower_bound(a.begin(), a.end(), l) - a.begin();
if(i < a.size() && a[i] <= r || !i) continue;
if(q1.back().first.first >= l && q1.back().first.second <= r) continue;
long long nxt = max(a[i - 1], q1.back().first.first);
long long dlt = (l - nxt) / i + 5;
while(l - dlt * i <= nxt) --dlt;
++dlt;
if(dlt <= 2) continue;
seg.M(0, n - 1, -dlt * i);
t += dlt;
}
seg = segment_tree(b);
t = 0;
sort(q2.begin(), q2.end()); reverse(q2.begin(), q2.end());
while(q2.size()) {
long long l = seg.Qx(seg.Qi(1)), r = seg.Qx(seg.Qi(seg.root->siz));
while(q2.size() && q2.back().first.first == t) {
ans[q2.back().second] = seg.Qx(q2.back().first.second);
q2.pop_back();
}
if(!q2.size()) break;
++t;
int i = lower_bound(a.begin(), a.end(), l) - a.begin() - 1, j;
long long lst = l - 1;
for (j = i + 1; j < a.size(); ++j) {
if(a[j] > r) break;
if(lst + 1 < a[j]) seg.M(seg.Qi(lst + 1 - l + 1), seg.Qi(a[j] - 1 - l + 1), -j);
lst = a[j];
}
if(lst + 1 <= r) seg.M(seg.Qi(lst + 1 - l + 1), seg.Qi(r - l + 1), -j);
for (int fuck = 0, j = i + 1; j < a.size(); ++j) {
if(a[j] > r) break;
seg.D(seg.Qi(a[j] - l + 1 - fuck));
++fuck;
}
l = seg.Qx(seg.Qi(1)), r = seg.Qx(seg.Qi(seg.root->siz));
i = lower_bound(a.begin(), a.end(), l) - a.begin();
if(i < a.size() && a[i] <= r || !i) continue;
if(q2.back().first.first == t) continue;
long long nxt = a[i - 1];
long long dlt = (l - nxt) / i + 5;
while(l - dlt * i <= nxt) --dlt;
++dlt;
dlt = min(dlt, q2.back().first.first - t);
if(dlt <= 2) continue;
seg.M(0, n - 1, -dlt * i);
t += dlt;
}
copy(ans.begin(), ans.end(), ostream_iterator<long long>(cout, "\n"));
return 0;
}