《算法竞赛进阶指南》打卡活动 #0x00 基本算法

101. 最高的牛

题目链接:https://www.acwing.com/problem/content/103/

作为一个银牌水平的主演数据结构的演员来说,这题现在发现非常好想,每个牛分配一个优先度。我搞一个区间线段树,每次update中间一段使得他们的优先度整体下降到比两端中较小的优先度还要小。然后反过来按照优先度分配身高。哈哈!根本不需要什么算法。不过每次都不询问为什么要线段树呢?差分不香吗?当然不香,每次询问当前的优先度啊!

const int MAXN = 10000;

int res[MAXN + 5];

struct SegmentTree {
#define ls (o<<1)
#define rs (o<<1|1)
    static const int MAXN = 10000;
    static const int INF = 0x3f3f3f3f;
    int ma[(MAXN << 2) + 5];
    int lz[(MAXN << 2) + 5];

    void PushUp(int o) {
        ma[o] = max(ma[ls], ma[rs]);
    }

    void PushDown(int o, int l, int r) {
        if(lz[o]) {
            lz[ls] += lz[o];
            lz[rs] += lz[o];
            //int m = l + r >> 1;
            ma[ls] += lz[o];
            ma[rs] += lz[o];
            lz[o] = 0;
        }
    }

    void Build(int o, int l, int r, int mx) {
        if(l == r) {
            ma[o] = mx;
        } else {
            int m = l + r >> 1;
            Build(ls, l, m, mx);
            Build(rs, m + 1, r, mx);
            PushUp(o);
        }
        lz[o] = 0;
    }

    void Update(int o, int l, int r, int ql, int qr, int v) {
        if(ql <= l && r <= qr) {
            lz[o] += v;
            ma[o] += v;
        } else {
            PushDown(o, l, r);
            int m = l + r >> 1;
            if(ql <= m)
                Update(ls, l, m, ql, qr, v);
            if(qr >= m + 1)
                Update(rs, m + 1, r, ql, qr, v);
            PushUp(o);
        }
    }

    int QueryMax(int o, int l, int r, int ql, int qr) {
        if(ql <= l && r <= qr) {
            return ma[o];
        } else {
            PushDown(o, l, r);
            int m = l + r >> 1;
            int res = -INF;
            if(ql <= m)
                res = QueryMax(ls, l, m, ql, qr);
            if(qr >= m + 1)
                res = max(res, QueryMax(rs, m + 1, r, ql, qr));
            return res;
        }
    }
#undef ls
#undef rs
} st;

pii a[MAXN + 5];
int ans[MAXN + 5];

void test_case() {
    int n, p, h, m;
    scanf("%d%d%d%d", &n, &p, &h, &m);
    st.Build(1, 1, n, n);
    while(m--) {
        int l, r;
        scanf("%d%d", &l, &r);
        if(l > r)
            swap(l, r);
        if(l == r || l == r - 1)
            continue;
        int mi = min(st.QueryMax(1, 1, n, l, l), st.QueryMax(1, 1, n, r, r));
        int ma = st.QueryMax(1, 1, n, l + 1, r - 1);
        if(ma < mi)
            continue;
        int d = ma - (mi - 1);
        st.Update(1, 1, n, l + 1, r - 1, -d);
    }
    for(int i = 1; i <= n; ++i)
        a[i] = {st.QueryMax(1, 1, n, i, i), i};
    sort(a + 1, a + 1 + n, greater());
    ans[a[1].second] = h;
    for(int i = 2; i <= n; ++i) {
        if(a[i].first == a[i - 1].first)
            ans[a[i].second] = h;
        else
            ans[a[i].second] = --h;
    }
    for(int i = 1; i <= n; ++i)
        printf("%d\n", ans[i]);
    return;
}

你可能感兴趣的:(《算法竞赛进阶指南》打卡活动 #0x00 基本算法)