1 条题解

  • 0
    @ 2025-8-24 22:45:38

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar kradcigam
    永不放弃之心,将成为贯穿逆境之光!

    搬运于2025-08-24 22:45:38,当前版本为作者最后更新于2023-04-19 15:51:15,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    赛时开始一眼线段树分治,交了几发都 T 了,就意识到事情不对。后来想了想发现势能分析不能带撤销。。。

    后来加了一些不能改变复杂度假了的优化,没过之后就自闭跑路了。。。

    赛后听别人说了个楼房重建就明白怎么做了。

    首先,我们离线下来把 aa 排序,去重(这样方便一点,不然权值线段树上的空节点得特判),线段树的叶子节点表示的是 [ti,ti+1)[t_i,t_{i+1}) 这段区间。为了方便,我们设 tn+1=inft_{n+1}=\inf

    我们维护当前线段树区间的 44 个值:

    1. 总共匹配了多少个值;
    2. 总共向右超出了多少个值;
    3. 匹配的答案是多少;
    4. 左区间超出部分的答案,若左区间超出部分在右区间依旧超出,那就不管了。

    考虑 pushup,分 22 种情况:

    1. 左区间超出部分在右区间依旧超出,则右区间被填满了;
    2. 左区间超出部分都可以在右区间插入,我们在右区间做线段树二分,计算出最后一个左区间超出部分的位置。由于需要减掉原始匹配的答案所以具体实现时需要维护 4(在 pushup 的时候记一下)。

    写的时候刚睡醒,一个地方 +- 打反了,调了半年。

    代码很短:

    #include <bits/stdc++.h>
    #define ls num << 1
    #define rs ls | 1
    #define li ls, l, mid
    #define ri rs, mid + 1, r
    #define int long long
    #define SZ(x) (int) x.size() - 1
    #define all(x) x.begin(), x.end()
    #define ms(x, y) memset(x, y, sizeof x)
    #define F(i, x, y) for (int i = (x); i <= (y); i++)
    #define DF(i, x, y) for (int i = (x); i >= (y); i--)
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    template <typename T> void chkmax(T &x, T y) { x = max(x, y); }
    template <typename T> void chkmin(T &x, T y) { x = min(x, y); }
    template <typename T> void read(T &x) {
    	x = 0; int f = 1; char c = getchar();
    	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
    	x *= f;
    }
    const int N = 1e5 + 10, MOD = 1e9 + 7, inv2 = (MOD + 1) / 2;
    int rt, tot, x[N], y[N], t[N];
    int qq(int l, int r) {
    	return ((r - l + 1) % MOD) * ((l + r) % MOD) % MOD * inv2 % MOD;
    }
    struct seg {
    	int out, sum, ans, lans;
    } tt[N * 4];
    pair <int, int> query(int num, int l, int r, int x) {
    	if (l == r) return make_pair(t[l] + tt[num].sum + x - 1, tt[num].ans);
    	int mid = (l + r) >> 1;
    	int cnt = t[mid + 1] - t[l] - tt[ls].sum;
    	if (x <= cnt) return query(ls, l, mid, x);
    	pair <int, int> ans = query(rs, mid + 1, r, x - cnt + tt[ls].out);
    	ans.second += tt[ls].ans + tt[num].lans;
    	return ans;
    }
    void pushup(int num, int l, int r) {
    	int mid = (l + r) >> 1;
    	int cnt = t[r + 1] - t[mid + 1] - tt[rs].sum;
    	if (cnt < tt[ls].out) {
    		tt[num].out = tt[rs].out + tt[ls].out - cnt;
    		tt[num].sum = tt[ls].sum + t[r + 1] - t[mid + 1];
    		tt[num].ans = tt[ls].ans + qq(t[mid + 1], t[r + 1] - 1);
    		tt[num].lans = -1;
    	} else {
    		tt[num].out = tt[rs].out;
    		tt[num].sum = tt[ls].sum + tt[rs].sum + tt[ls].out;
    		pair <int, int> pos = make_pair(t[mid + 1] - 1, 0);
    		if (tt[ls].out) pos = query(rs, mid + 1, r, tt[ls].out);
    		tt[num].lans = qq(t[mid + 1], pos.first) - pos.second;
    		tt[num].ans = tt[ls].ans + tt[rs].ans + tt[num].lans;
    	}
    }
    void change(int num, int l, int r, int x, int y) {
    	if (l == r) {
    		tt[num].sum = min(y, t[l + 1] - t[l]);
    		tt[num].ans = qq(t[l], t[l] + tt[num].sum - 1);
    		tt[num].out = y - tt[num].sum;
    		return;
    	} int mid = (l + r) >> 1;
    	if (mid >= x) change(li, x, y);
    	else change(ri, x, y);
    	pushup(num, l, r);
    }
    signed main() {
    	int n; read(n);
    	F(i, 1, n) read(x[i]), read(y[i]), t[i] = x[i];
    	sort(t + 1, t + n + 1);
    	int m = unique(t + 1, t + n + 1) - t - 1;
    	t[m + 1] = 1e18;
    	F(i, 1, n) {
    		change(1, 1, m, lower_bound(t + 1, t + m + 1, x[i]) - t, y[i]);
    		cout << (tt[1].ans % MOD + MOD) % MOD << '\n';
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    8461
    时间
    6000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者