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;
}
posted @ 2018-10-08 09:33  King_George  阅读(552)  评论(0编辑  收藏  举报