《算法竞赛进阶指南》打卡活动 #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<pii>());
    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;
}

原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12254585.html

时间: 2024-11-08 00:21:32

《算法竞赛进阶指南》打卡活动 #0x00 基本算法的相关文章

《算法竞赛进阶指南》学习总结 #include&lt;algorithm&gt;

今天下午大致学完了进阶指南中algorithm头文件下的内容,在这里进行一个总结.   reverse翻转   顾名思义,reverse进行的操作就是翻转原来的顺序,理解非常简单,故不赘述. 操作样例: #include<bits/stdc++.h> using namespace std; vector<int>a; int b[233]; int main() { int na,nb; //vector的实现 scanf("%d",&na); for

《算法竞赛进阶指南》学习总结 二分与三分

首先......我是一个很菜很菜的萌新,所以这篇文章写得很详细,有很多我自己的口水话方便我理解,请各位谨慎食用qwq 以前在网上找过很多介绍二分的博客,但都感觉对萌新不太友好,反正我当时连跳石头都没看懂,所以决定自己写一篇!其中有我的想法,也借鉴了书里的很多内容,感谢lyd. 二分答案,顾名思义,就是对我们所需要的答案进行二分,对我们要求的值进行二分.二分的基础用法是在单调序列或者单调函数当中查找,当答案具有单调性,我们就可以采用二分来计算,当然还有三分,在后面我会详细讲到 整数集合上的二分 在

算法竞赛进阶指南 0x00

0101a^b 快速幂模板,写一下快速幂的原理. 我们知道,一个数\(n\)在二进制(也可以是其他进制)下可以被表示为\(a_1+a_2*2^1+a_3*2^2+...+a_m*2^{m-1}\).那么我们可以考虑将其分拆成二进制状态下的每一位,然后做幂运算.这样做的时间复杂度为\(O(log_2 n)\). 实现的过程类似于倒过来的分治(当然也可以直接分治实现),原理基于以下的式子. 对于k为偶数,\(n^k=(n^2)^{k/2}\). 对于k为奇数,\(n^k=n*(n^2)^{(k-1)

《算法竞赛进阶指南》0.8总结与练习(1)

116. 飞行员兄弟 "飞行员兄弟"这个游戏,需要玩家顺利的打开一个拥有16个把手的冰箱. 已知每个把手可以处于以下两种状态之一:打开或关闭. 只有当所有把手都打开时,冰箱才会打开. 把手可以表示为一个4х4的矩阵,您可以改变任何一个位置[i,j]上把手的状态. 但是,这也会使得第i行和第j列上的所有把手的状态也随着改变. 请你求出打开冰箱所需的切换把手的次数最小值是多少. 输入格式 输入一共包含四行,每行包含四个把手的初始状态. 符号"+"表示把手处于闭合状态,而

算法竞赛进阶指南做题记录

基本算法 递归与递推 费解的开关 Strange Towers of Hanoi Sumdiv Fractal Streets 前缀和与差分 激光炸弹 IncDec Sequence Tallest Cow 二分 Best Cow Fences 排序 Cinema 货舱选址 七夕祭 Running Median 第K大数 Ultra-QuickSort 奇数码问题 原文地址:https://www.cnblogs.com/Maktub-blog/p/11009723.html

算法竞赛进阶指南 走廊泼水节

原题链接 题目描述 给定一棵N个节点的树,要求增加若干条边,把这棵树扩充为完全图,并满足图的唯一最小生成树仍然是这棵树. 求增加的边的权值总和最小是多少. 输入格式 第一行包含整数t,表示共有t组测试数据. 对于每组测试数据,第一行包含整数N. 接下来N-1行,每行三个整数X,Y,Z,表示X节点与Y节点之间存在一条边,长度为Z. 输出格式 每组数据输出一个整数,表示权值总和最小值. 每个结果占一行. 数据范围 \(N \le 6000,Z \le 100\) 输入样例: 2 3 1 2 2 1

bzoj 1787 &amp;&amp; bzoj 1832: [Ahoi2008]Meet 紧急集合(倍增LCA)算法竞赛进阶指南

题目描述 原题连接 Y岛风景美丽宜人,气候温和,物产丰富. Y岛上有N个城市(编号\(1,2,-,N\)),有\(N-1\)条城市间的道路连接着它们. 每一条道路都连接某两个城市. 幸运的是,小可可通过这些道路可以走遍Y岛的所有城市. 神奇的是,乘车经过每条道路所需要的费用都是一样的. 小可可,小卡卡和小YY经常想聚会,每次聚会,他们都会选择一个城市,使得3个人到达这个城市的总费用最小. 由于他们计划中还会有很多次聚会,每次都选择一个地点是很烦人的事情,所以他们决定把这件事情交给你来完成. 他们

《算法竞赛进阶指南》刷题记录

总算闲下来一些辣!然后最近发现其实看书是真真很有效但是一直没有落实!所以决定落实一下这段时间把这本书看完题目做完! 然后发现还有挺多题目挺巧妙的于是一堆博客预警,,,可能最近会写很多比较水(但是我还是不会做)的题目的题解 先放个空壳子晚上再来写qwq 原文地址:https://www.cnblogs.com/lqsukida/p/9988445.html

【算法竞赛进阶指南】USACO07Tallest Cow

前缀和,利用左右端点操作代替对区间的操作,从而优化输入,最后进行一次前缀和的操作,求得结果,这道题里面有个很关键的问题,就是需要去重,本来我想用set,但貌似有点鬼畜,算了,利用map去重,还有pair类型(学一下) #include <iostream> #include <algorithm> #include <map> #include <utility> using namespace std; map<pair<int,int>