CF1034D

题意

给定 \(n\) 个区间 \([l_1,\ r_1],\ [l_2,\ r_2],\ ...,\ [l_n,\ r_n]\)。定义 \(f(i,\ j)\ (i\ \leq\ j)\)\([l_i,\ r_i],\ [l_{i\ +\ 1},\ r_{i\ +\ 1}],\ ...,\ [l_j,\ r_j]\) 的并的长度。
求长度前 \(k\) 大的 \(f\) 值的和。

\(1\ \leq\ n\ \leq\ 300000,\ 1\ \leq\ k\ \leq\ \min\{\frac{n\ (n\ +\ 1)}{2},\ 10^9\},\ 1\ \leq\ l_i\ <\ r_i\ \leq\ 10^9\)

做法1

二分第 \(k\) 大的 \(f\)\(len\),考虑如何求有多少个 \(f\) 值比 \(len\) 大。
可以发现 \(f\) 是单调的,所以使用 two-pointers 求解。设当前扫到的为 \(f(x,\ y)\),如果能维护直线上 \([i,\ i\ +\ 1)\) 最后一次被哪一个在 \(y\) 之前的区间所覆盖就可以快速处理左右端点移动 \(1\) 之后求 \(f\) 值的问题。可以发现当遇到一个新的区间 \(k\),暴力将 \(k\) 区间上所有非 \(k\) 的标记赋为 \(k\) 的总复杂度为 \(O(n)\) 次。简略证明如下,覆盖区间时,如果有一个之前的区间被 \(k\) 区间整个覆盖住,那么进行 \(O(1)\) 次操作删除这个区间,总势能 \(-\ 1\)。如果之前区间与第 \(k\) 个区间相交,但无覆盖关系,由于这样的区间最多只有 \(2\) 个,总势能不变。如果 \(k\) 被之前区间覆盖,进行 \(O(1)\) 次操作将总势能增加\(1\)。并最后花费 \(O(1)\) 次操作覆盖 \(k\) 区间,总势能 \(+\ 1\)。可以直接用 \(set\) 维护。但如果每次二分后都这样做需要 \(O(n\ log^2\ n)\),考虑优化。
优化维护区间不可行,考虑能否预处理。由于已经证明只有 \(O(n)\) 次操作,所以可以发现对于一个 \(i\)\(f(j,\ i)\) 只有在覆盖 \(i\) 区间时处理过 \(j\) 区间的时候才会有 \(f(j,\ i)\ \neq\ f(j\ -\ 1,\ i)\),因此总共只有 \(O(n)\) 个不同的 \(f\) 值,预处理之后二分的时候 two-pointers 扫一下即可。

时间复杂度 \(O(n\ log\ n)\)

代码

#include <bits/stdc++.h>

#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif

#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif

using namespace std;

const int maxn = 3e5 + 10;

int n, k;
vector<pair<int, int> > dlt[maxn];
set<pair<pair<int, int>, int> > s;
int f[maxn];
long long g[maxn], gi[maxn];

int lowbit(int i) { return i & (-i); }
void M(int i, long long x) { for (; i <= n; i += lowbit(i)) g[i] += x; return; }
long long Q(int i) { long long x = 0; for(; i; i ^= lowbit(i)) x += g[i]; return x; }
void Mi(int i, long long x) { for (; i <= n; i += lowbit(i)) gi[i] += x; return; }
long long Qi(int i) { long long x = 0; for(; i; i ^= lowbit(i)) x += gi[i]; return x; }

long long calc(int mid) {
	memset(f, 0, sizeof f);
	int i = 1, j = 0, len = 0;
	while(f[1] < mid) {
		++j;
		if(j > n) return 0;
		int s = 0;
		for (auto &t: dlt[j]) s += t.second, f[t.first] += t.second;
		f[j + 1] -= s;
	}
	len = f[1];
	long long ret = n - j + 1;
	while((++i) <= n) {
		len += f[i];
		while(len < mid) {
			++j;
			if(j > n) return ret;
			int s = 0;
			for (auto &t: dlt[j]) {
				s += t.second;
				if(t.first <= i) len += t.second;
				else f[t.first] += t.second;
			}
			f[j + 1] -= s;
		}
		ret += (n - j + 1);
	}
	return ret;
}

long long sum(int mid) {
	memset(g, 0, sizeof g);
	memset(gi, 0, sizeof gi);
	memset(f, 0, sizeof f);
	int i = 1, j = 0, len = 0;
	while(f[1] < mid) {
		++j;
		if(j > n) return 0;
		int s = 0;
		for (auto &t: dlt[j]) s += t.second, f[t.first] += t.second;
		f[j + 1] -= s;
	}
	len = f[1];
	for (int i = j + 1; i <= n; ++i) for (auto &t: dlt[i]) M(t.first, t.second), Mi(t.first, (long long) t.second * i);
	long long ret = Q(i) * (n + 1) - Qi(i) + (long long) len * (n - j + 1);
	while((++i) <= n) {
		len += f[i];
		while(len < mid) {
			++j;
			if(j > n) break;
			int s = 0;
			for (auto &t: dlt[j]) {
				s += t.second;
				if(t.first <= i) len += t.second;
				else f[t.first] += t.second;
				M(t.first, -t.second), Mi(t.first, -(long long) t.second * j);
			}
			f[j + 1] -= s;
		}
		if(j > n) break;
		ret += Q(i) * (n + 1) - Qi(i) + (long long) len * (n - j + 1);
	}
	return ret;
}

int main() {
	scanf("%d%d", &n, &k);
	s.insert(make_pair(make_pair(1, 999999999), 0));
	for (int i = 1; i <= n; ++i) {
		int l, r; scanf("%d%d", &l, &r); --r;
		for(;;) {
			auto it = s.lower_bound(make_pair(make_pair(l, -1), -1));
			if(it == s.end() || it->first.second > r) break;
			dlt[i].push_back(make_pair(it->second + 1, it->first.second - it->first.first + 1));
			s.erase(it);
		}
		auto it = s.lower_bound(make_pair(make_pair(l, -1), -1));
		if(it != s.end() && it->first.first <= r) {
			int x = it->first.first, y = it->first.second, z = it->second;
			s.erase(it);
			dlt[i].push_back(make_pair(z + 1, r - x + 1));
			s.insert(make_pair(make_pair(r + 1, y), z));
		}
		it = s.lower_bound(make_pair(make_pair(l, -1), -1));
		if(it != s.begin()) {
			--it;
			if(it->first.second >= l) {
				int x = it->first.first, y = it->first.second, z = it->second;
				s.erase(it);
				if(y <= r) {
					dlt[i].push_back(make_pair(z + 1, y - l + 1));
					s.insert(make_pair(make_pair(x, l - 1), z));
				}
				else {
					dlt[i].push_back(make_pair(z + 1, r - l + 1));
					s.insert(make_pair(make_pair(x, l - 1), z));
					s.insert(make_pair(make_pair(r + 1, y), z));
				}
			}
		}
		s.insert(make_pair(make_pair(l, r), i));
	}
	int lb = 0, rb = 1000000000;
	while(lb <= rb) {
		int mid = lb + rb >> 1;
		long long f = calc(mid);
		if(f >= k) lb = mid + 1;
		else rb = mid - 1;
	}
	printf("%"LLFORMAT"d\n", sum(lb) + (long long) (lb - 1) * (k - calc(lb)));
	return 0;
}
posted @ 2018-09-28 12:15  King_George  阅读(418)  评论(0编辑  收藏  举报