标签:for operator iter print cto comet int 要求 com
实际上时有题解的:zbk的题解
第一道CF 3500 的题。
还是根据诸多弱化版的思路,我们维护数轴上每个点(或者说每个“段”)最后一次被覆盖的时间,并在每个右端点上计算答案。对于一个右端点来说,记 \(f(p)\) 表示从 \(p\) 到右端点的并的长度。右端点向右扩展1,意味着右端点所覆盖的那些“段”的区间要永远被删除(贪心地想,以后的右端点都会包含新区间,那么那些被覆盖的部分就永远用不到了),新区间可以在 \(1...r\) 中起作用。发现就是区间修改操作。每次最多会分裂两个“段”,每个段最多被加入一次删除一次,那么总时间复杂度是 \(O(ng(n))\),其中 \(g(n)\) 表示用数据结构维护规模为 \(O(n)\) 的复杂度。用 set 和树状数组能做到 \(O(nlogn)\)
现在我们能快速求出 \(l...r\) 的并了,但是我们并没有“询问”,而是要求前 \(k\) 大。一看 \(k \le 10^9\) 就知道不会是超级钢琴模型,那么我们可以尝试二分出最小的那个并的长度,看看够不够 \(k\) 个。显然最小的那个并的长度限制越大,我们得到的并的个数就越少。这样,我们要做的就是求出答案小于等于 \(limi\) 的并的个数以及并的和。
发现并对于区间的区间的左右端点是单调的。那么我们可以考虑双指针维护以 \(r\) 为右端点的最靠右的 \(l\)。然后就 \(O(nlogLlogn)\)了。(\(L\) 为并的长度的值域)
然而我们发现我们所有查询操作的查询位置也是单调递增的,并且我们的树状数组只是用来维护个前缀和。那么我们可以随便搞搞就能砍掉那个树状数组的 \(log\)。不过还有个set 维护线段覆盖情况的 \(log\),这个也好砍,直接在二分外面用 \(vector\) 记录我们会进行的操作,二分里面直接扫 \(vector\) 即可。
总复杂度:\(O(nlogL)\)
关键代码:(实现时我学着 zbk 二分用的倍增写法)
int n, k;
struct node {
int l, r, t;
bool operator <(const node a) const { return l < a.l; }
};
set<node> st;
inline void Split(int pos) {
set<node>::iterator it = st.lower_bound((node){pos, 0, 0});
if (it == st.begin()) return ;
--it;
node nd = *it;
if (nd.r <= pos) return ;
int l = nd.l, r = nd.r, t = nd.t;
st.erase(it);
st.insert((node){l, pos, t}); st.insert((node){pos, r, t});
}
vector<PII> opts[N];
ll tag[N], ans;
inline bool che(int limi) {
memset(tag, 0, sizeof(tag));
ll cnt = 0, tot = 0, nw = 0, sum = 0;
int np = 0;
for (register int i = 1; i <= n; ++i) {
for (register uint j = 0; j < opts[i].size(); ++j) {
int p = opts[i][j].fi, v = opts[i][j].se;
if (p <= np) {
sum += 1ll * (np - p + 1) * v;
nw += v;
} else {
tag[p] += v;
}
}
while (np != i && nw + tag[np + 1] >= limi) ++np, nw += tag[np], sum += nw;
tot += sum; cnt += np;
}
if (cnt < k) return false;
ans = tot - (cnt - k) * limi;
return true;
}
int main() {
read(n); read(k);
for (register int i = 1; i <= n; ++i) {
int l, r; read(l), read(r);
Split(l), Split(r);
bool fg = false;
set<node>::iterator it, lstit = st.end();
for (it = st.lower_bound((node){l, 0, 0}); it != st.end() && (*it).r <= r; lstit = it, ++it) {
node nd = *it; int t = nd.t, len = nd.r - nd.l;
opts[i].push_back(MP(1, -len)); opts[i].push_back(MP(t + 1, len));
if (!fg) fg = true;
else st.erase(lstit);
}
opts[i].push_back(MP(1, r - l));
opts[i].push_back(MP(i + 1, -(r - l)));
if (lstit != st.end()) st.erase(lstit);
st.insert((node){l, r, i});
}
int s = 0;
for (int d = 29; ~d; --d)
if (che(s | (1 << d))) s |= (1 << d);
printf("%lld\n", ans);
return 0;
}
CF1034D Intervals of Intervals
标签:for operator iter print cto comet int 要求 com
原文地址:https://www.cnblogs.com/JiaZP/p/13594241.html