首页 > 其他分享 >洛谷P8868 [NOIP2022] 比赛

洛谷P8868 [NOIP2022] 比赛

时间:2022-12-28 16:12:38浏览次数:55  
标签:洛谷 int pos cy cx lson add NOIP2022 P8868

离线所有询问(按右端点排序),然后枚举右端点 \(r\)。

记 \(X_l\) 为 \(a\) 在区间 \([l, r]\) 中的最大值,\(Y_l\) 为 \(b\) 在区间 \([l, r]\) 中的最大值。

在枚举的过程中,对每个 \(l\), \(f(i) \leftarrow X_lY_l\),则对于一个右端点为 \(r\) 的询问 \([x, r]\),其答案为 \(\sum\limits_{i = l}^r f(i)\)。

这样的时间复杂度是 \(O(n^2 + nq)\),可以拿到 \(20\) 分。

考虑加速 \(X, Y, f\) 的计算,也就是要写一种数据结构,能够实现:

  • \(X, Y, f\) 的区间修改。
  • \(f\) 的区间和查询。

自然想到线段树。

\(X, Y\) 都会被修改,因此维护 \(sumf, sumX, sumY, sumXY\) 四个值和 \(cx, cy, tx, ty,txy, add\) 六个懒标记。

四个值的意义就是字面意义。

\(cx\) 表示当前区间的 \(X\) 值会被修改为 \(cx\),同理 \(cy\) 表示当前区间的 \(Y\) 值会被修改为 \(cy\)。

\(tx\) 表示累加进 \(sumf\) 中的 \(x\) 的倍数,\(ty\) 表示累加进 \(sumf\) 中的 \(y\) 的倍数,\(txy\) 表示累加进 \(sumf\) 中的 \(xy\) 的倍数,\(add\) 表示要累加进 \(sumf\) 的值。

pushup 比较常规,四个值分别为左右子之和即可。难点在 pushdown。

以下放左子(\(pos\) 下放至 \(lson\))为例,先处理贡献再覆盖,即:

  • 若 \(cx_{lson}\) 和 \(cy_{lson}\) 都有值,则将 \(cx_{lson}\) 和 \(cy_{lson}\) 的贡献都直接归到 \(add_{lson}\) 中,即:

\[add_{lson} \leftarrow cx_{lson} \times tx_{pos} + cy_{lson} \times ty_{lson} + cx_{lson} \times cy_{lson} \times txy_{pos} + add_{pos} \]

  • 若仅 \(cx_{lson}\) 有值,则将 \(cx_{lson}\) 的贡献归到 \(add_{lson}\) 和 \(ty_{lson}\) 中,即:

\[add_{lson} \leftarrow cx_{lson} \times tx_{pos} + add_{pos} \\ ty_{lson} \leftarrow cx_{lson} \times txy_{pos} + ty_{pos} \]

  • 相似地,若仅 \(cy_{lson}\) 有值,则将 \(cy_{lson}\) 的贡献归到 \(add_{lson}\) 和 \(tx_{lson}\) 中,即:

\[add_{lson} \leftarrow cy_{lson} \times ty_{pos} + add_{pos} \\ tx_{lson} \leftarrow cy_{lson} \times txy_{pos} + tx_{pos} \]

  • 否则,也就是 \(cx_{lson}\) 和 \(cy_{lson}\) 都没有值,直接累加即可。

然后再根据 \(cx_{pos}\) 和 \(cy_{pos}\) 的值的有无决定是否覆盖 \(cx_{lson}, cy_{lson}\)。

至此,标记就更新完了,接下来考虑值的更新。

\[sumf_{lson} \leftarrow sumX_{lson} \times tx_{pos} + sumY_{lson} \times ty_{pos} + sumXY \times txy_{pos} + add_{pos} \]

然后再根据 \(cx_{pos}\) 和 \(cy_{pos}\) 的值的有无决定是否更新 \(sumX, sumY, sumXY\)。

最后就是要明确每次我们要更新哪些区间,查询哪个区间。

通过单调栈预处理出每个 \(a_i\) 左侧第一个大于等于 \(a_i\) 的元素的下标 \(la_i\) 和每个 \(b_i\) 左侧第一个大于等于 \(b_i\) 的元素的下标 \(lb_i\)。易知 \(a_i\) 对 \([1, la_i]\) 的答案没有影响,同理,\(b_i\) 对 \([1, lb_i]\) 的答案没有影响。

因此,每次更新 \([la_i + 1, r]\) 的 \(X\),\([lb_i + 1, r]\) 的 \(Y\) 和 \([1, r]\) 的 \(f\),然后对每个右端点为 \(r\) 的询问 \([x, r]\),查询 \([x, r]\) 的区间 \(f\) 和即可。

时间复杂度 \(O(n \log n)\),快得飞起。

代码:

#include <bits/stdc++.h>

#define MAXN 250100
#define lson pos << 1
#define rson pos << 1 | 1

using namespace std;

typedef unsigned long long ull;

int n, m;
ull a[MAXN], b[MAXN], ans[MAXN];
int top, stk[MAXN], la[MAXN], lb[MAXN];

struct Tag {
    ull cx, cy, tx, ty, txy, add;

    void operator*=(const Tag &rhs) { // 更新标记
        if (cx && cy) {
            add += cx * rhs.tx + cy * rhs.ty + cx * cy * rhs.txy + rhs.add;
        } else if (cx) {
            add += cx * rhs.tx + rhs.add;
            ty += cx * rhs.txy + rhs.ty;
        } else if (cy) {
            add += cy * rhs.ty + rhs.add;
            tx += cy * rhs.txy + rhs.tx;
        } else {
            tx += rhs.tx; ty += rhs.ty; txy += rhs.txy; add += rhs.add;
        }
        if (rhs.cx) cx = rhs.cx;
        if (rhs.cy) cy = rhs.cy;
    }

    bool exist() {
        return cx || cy || tx || ty || txy || add; // 判断整个 Tag 是否有值
    }
};

struct Seg {
    ull sx[MAXN << 2], sy[MAXN << 2], sxy[MAXN << 2], f[MAXN << 2];
    Tag lazy[MAXN << 2];

    void fix(int pos, int len, Tag t) { // 更新值
        f[pos] += sx[pos] * t.tx + sy[pos] * t.ty + sxy[pos] * t.txy + t.add * len;
        if (t.cx && t.cy) {
            sx[pos] = t.cx * len; sy[pos] = t.cy * len;
            sxy[pos] = t.cx * t.cy * len;
        } else if (t.cx) {
            sx[pos] = t.cx * len;
            sxy[pos] = t.cx * sy[pos];
        } else if (t.cy) {
            sy[pos] = t.cy * len;
            sxy[pos] = t.cy * sx[pos];
        }
    }

    void pushup(int pos) {
        sx[pos] = sx[lson] + sx[rson];
        sy[pos] = sy[lson] + sy[rson];
        sxy[pos] = sxy[lson] + sxy[rson];
        f[pos] = f[lson] + f[rson];
    }

    void pushdown(int pos, int len) {
        if (!lazy[pos].exist()) return;
        lazy[lson] *= lazy[pos]; lazy[rson] *= lazy[pos];
        fix(lson, len - (len >> 1), lazy[pos]); fix(rson, len >> 1, lazy[pos]);
        lazy[pos] = {0, 0, 0, 0, 0, 0};
    }

    void upd(int pos, int l, int r, int x, int y, Tag t) {
        if (x <= l && r <= y) {
            // 更新标记和值
            // 与 pushdown 相同,只不过这时候是将 t 下放到 pos。
            lazy[pos] *= t;
            fix(pos, r - l + 1, t);
            return;
        }
        pushdown(pos, r - l + 1);
        int mid = (l + r) >> 1;
        if (x <= mid) upd(lson, l, mid, x, y, t);
        if (y > mid) upd(rson, mid + 1, r, x, y, t);
        pushup(pos);
    }

    ull query(int pos, int l, int r, int x, int y) {
        if (x <= l && r <= y) return f[pos];
        pushdown(pos, r - l + 1);
        int mid = (l + r) >> 1;
        ull res = 0;
        if (x <= mid) res += query(lson, l, mid, x, y);
        if (y > mid) res += query(rson, mid + 1, r, x, y);
        return res;
    }
} T;

struct Node {
    int l, r, id;

    bool operator<(const Node &rhs) const {
        return r < rhs.r;
    }
} ask[MAXN];

template<typename _T>
void read(_T &_x) {
    _x = 0;
    _T _f = 1;
    char _ch = getchar();
    while (_ch < '0' || '9' < _ch) {
        if (_ch == '-') _f = -1;
        _ch = getchar();
    }
    while ('0' <= _ch && _ch <= '9') {
        _x = (_x << 3) + (_x << 1) + (_ch & 15);
        _ch = getchar();
    }
    _x *= _f;
}

template<typename _T>
void write(_T _x) {
    if (_x < 0) {
        putchar('-');
        _x = -_x;
    }
    if (_x > 9) write(_x / 10);
    putchar('0' + _x % 10);
}

int main() {
    read(n); read(n);
    for (int i = 1; i <= n; i++) read(a[i]);
    for (int i = 1; i <= n; i++) read(b[i]);
    read(m);
    // 单调栈预处理 la[] 和 lb[],从右向左处理
    // 能将 a[j] 弹出的 a[i] 即为 a[j] 左侧第一个大于等于 a[j] 的元素
    for (int i = 1; i <= m; i++) {
        ask[i].id = i;
        read(ask[i].l); read(ask[i].r);
    }
    for (int i = n; i; i--) {
        while (top && a[i] >= a[stk[top]]) la[stk[top--]] = i;
        stk[++top] = i;
    }
    top = 0;
    for (int i = n; i; i--) {
        while (top && b[i] >= b[stk[top]]) lb[stk[top--]] = i;
        stk[++top] = i;
    }
    sort(ask + 1, ask + m + 1);
    int cur = 1;
    for (int i = 1; i <= n; i++) {
        // 直接以下放 Tag 的形式更新,省得写 3 个 upd 函数
        T.upd(1, 1, n, la[i] + 1, i, Tag{a[i], 0, 0, 0, 0, 0});
        T.upd(1, 1, n, lb[i] + 1, i, Tag{0, b[i], 0, 0, 0, 0});
        T.upd(1, 1, n, 1, i, Tag{0, 0, 0, 0, 1, 0});
        // 统计答案
        while (cur <= m && ask[cur].r == i) {
            ans[ask[cur].id] = T.query(1, 1, n, ask[cur].l, i);
            cur++;
        }
        if (cur > m) break;
    }
    for (int i = 1; i <= m; i++) {
        write(ans[i]); putchar('\n');
    }
    return 0;
}

标签:洛谷,int,pos,cy,cx,lson,add,NOIP2022,P8868
From: https://www.cnblogs.com/chy12321/p/17010350.html

相关文章

  • NOIP2022 游记
    ChangeLog:2022.12.28开坑。书接上回。由于CSP考的还行,被教练允许停课一周(指上午文化课,下午OI)。仍然和CSP停课的巨佬一起。由于这段时间下午主要是补他们上午......
  • 洛谷 P5363 / LOJ #3114 「SDOI2019」移动金币
    洛谷传送门LOJ传送门不错的博弈+计数。不难发现题中的游戏是阶梯Nim的变体。若设\(a_i\)为第\(i\)枚金币的位置,令\(\foralli\in[2,m],\b_i=a_i-a_{i-......
  • 洛谷 SP11414 / SPOJ COT3 Combat on a tree
    洛谷传送门SPOJ传送门考虑计算出以\(u\)为根的子树的\(\text{SG}\)值。在\(u\)子树内选择一个白点\(w\),将\(w\tou\)上的所有点删去,原树会变成森林,\(\text{S......
  • 洛谷P4146 序列终结者 题解 splay tree
    题目链接:https://www.luogu.com.cn/problem/P4146题目大意:支持:区间更新(+x)区间翻转区间查询(最大值)解题思路:几乎和AcWing2437.Splay这题一模一样。示例程序:#inc......
  • 洛谷 P5721 【入门3】循环结构
    P5721【深基4.例6】数字直角三角形1.题目描述给出 n,请输出一个直角边长度是 n 的数字直角三角形。所有数字都是 2 位组成的,如果没有 2 位则加上前导 00。2.输......
  • AcWing1134/洛谷P1144 最短路计数
    AcWing传送门洛谷传送门题目大意\(\qquad\)给一个无向图,边权都是\(1\),求出以\(1\)为源点,到各个点(\(1\simn\))的最短路数量解题思路\(\qquad\)边权都是\(1\)的图中最......
  • 洛谷P2024 [NOI2001] 食物链
    slojP2577.食物链题目大意说实话,我做对了之后都还是有点懵语文不好都这么招歧视了吗,我太难了三类动物A,B,C,A吃B,B吃C,C吃A。给出若干关系,判断第几个关系是错误的......
  • 洛谷P1196 [NOI2002] 银河英雄传说
    slojP2577.食物链题目大意一个序列初始编号为1,2,3,,,30000有2个操作:mij合并第i列和第j列,将第i列头部接到第j列尾部cIj询问i号和j号之间的数量,若......
  • Solution -「COCI 2009-2010」「洛谷 P8076」RESTORAN
    \(\mathscr{Description}\)  Link.  给定一个含\(n\)个点\(m\)条边的简单图,求一种边二染色方案,使得所有\(\deg\ge2\)的结点都邻接于两种颜色的边.  \(n......
  • AcWing341. 洛谷P1073, NOIP2009 最优贸易
    AcWing题目传送门洛谷题目传送门题目大意\(~~~~~~\)一个投机倒把的奸商想要通过城市不太健全的贸易系统坑点钱,任意城市都可以买入或者卖出水晶球,他想尽量在便宜的城市买......