当前位置: 首页 > news >正文

luoguP4647 [IOI2007] sails 船帆

https://www.luogu.org/problemnew/show/P4647

首先发现答案与顺序无关,令 $ x_i $ 表示高度为 $ i $ 的那一行帆的个数,第 $ i $ 行对答案的贡献为 $ \frac{x_i * (x_i - 1)}{2} $

先把旗杆按照高度从小到大排序,有一个显然的贪心是每次选择能放的地方帆最少的一行放一个帆,最少的一行放一个帆对答案的贡献一定最小,而后面的旗杆高度更高,能选择放帆的地方更多,这样可以保证答案最小(可以感性理解一下

那么我们的做法就出来了,对于旗杆 $ i $ 选择当前能放帆的最少的 $ k_i $ 行,放上帆,这个操作用平衡树实现,将原序列前 $ k $ 小拿出,加上 $ 1 $ 后放回去,这个时候可能会使平衡树的性质被打破,如 $ 0 $ $ 0 $ 将第一个数加 $ 1 $ 再放回去就变成了 $ 1 $ $ 0 $,所以对于分裂出来的前 $ k $ 小中的最大值还要再次分裂,如 $ 0 $ $ 1 $ $ 1 $ $ 1 $ $ 2 $ 前 $ 3 $ 小要加 $ 1 $,先分裂成 $ 0 $ $ 1 $ $ 1 $ 和 $ 1 $ $ 2 $,然后分裂成 $ 0 $ ,$ 1 $ $ 1 $ 和 $ 1 $ $ 2 $,区间加后放回原序列,先变成 $ 1 $ {这里放原来的 $ 1 $ $ 1 $ } $ 2 $,然后变成 {这里放原来的 $ 0 $} $ 1 $ {这里放原来的 $ 1 $ $ 1 $ } $ 2 $,即 $ 0 $ $ 1 $ $ 1 $ $ 1 $ $ 2 $,可以使用 splay 实现

#include <bits/stdc++.h>
#define Fast_cin ios::sync_with_stdio(false), cin.tie(0);
#define rep(i, a, b) for(register int i = a; i <= b; i++)
#define per(i, a, b) for(register int i = a; i >= b; i--)
#define DEBUG(x) cerr << "DEBUG" << x << " >>> " << endl;
using namespace std;

typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef long long ll;

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

template <typename T>
void print(T x) {
    if(x < 0) putchar('-'), x = -x;
    if(x < 10) putchar(x + 48);
    else print(x / 10), putchar(x % 10 + 48);
}

template <typename T>
void print(T x, char t) {
    print(x); putchar(t);
}

template <typename T>
struct hash_map_t {
    vector <T> v, val, nxt;
    vector <int> head;
    int mod, tot, lastv;
    T lastans;
    bool have_ans;

    hash_map_t (int md = 0) {
        head.clear(); v.clear(); val.clear(); nxt.clear(); tot = 0; mod = md;
        nxt.resize(1); v.resize(1); val.resize(1); head.resize(mod);
        have_ans = 0;
    }

    bool count(int x) {
        int u = x % mod;
        for(register int i = head[u]; i; i = nxt[i]) {
            if(v[i] == x) {
                have_ans = 1;
                lastv = x;
                lastans = val[i];
                return 1;
            }
        }
        return 0;
    }

    void ins(int x, int y) {
        int u = x % mod;
        nxt.push_back(head[u]); head[u] = ++tot;
        v.push_back(x); val.push_back(y);
    }

    int qry(int x) {
        if(have_ans && lastv == x) return lastans;
        count(x);
        return lastans;
    }
};

const int N = 1e5 + 5;

struct ele {
    int h, gs;
    bool operator < (const ele A) const { return h < A.h; }
} a[N];

int ch[N][2], val[N], tag[N], siz[N], n, root;

inline void update(int u) { siz[u] = siz[ch[u][0]] + siz[ch[u][1]] + 1; }

inline void add_tag(int u, int x) { if(u <= 100000) val[u] += x; tag[u] += x; }

inline void pushdown(int u) {
    if(tag[u]) {
        if(ch[u][0]) add_tag(ch[u][0], tag[u]);
        if(ch[u][1]) add_tag(ch[u][1], tag[u]);
        tag[u] = 0;
    }
}

inline void rotate(int &u, int d) {
    int tmp = ch[u][d];
    ch[u][d] = ch[tmp][d ^ 1];
    ch[tmp][d ^ 1] = u;
    update(u); update(tmp);
    u = tmp;
}

void splay(int &u, int k) {
    pushdown(u);
    int ltree = siz[ch[u][0]];
    if(ltree + 1 == k) return;
    int d = k > ltree;
    pushdown(ch[u][d]);
    int k2 = d ? k - ltree - 1 : k;
    int ltree2 = siz[ch[ch[u][d]][0]];
    if(ltree2 + 1 != k2) {
        int d2 = k2 > ltree2;
        splay(ch[ch[u][d]][d2], d2 ? k2 - ltree2 - 1 : k2);
        if(d == d2) rotate(u, d); else rotate(ch[u][d], d2);
    }
    rotate(u, d);
}

int find(int u, int x) {
    pushdown(u);
    if(!u) return 0;
    if(x > val[u]) return siz[ch[u][0]] + 1 + find(ch[u][1], x);
    return find(ch[u][0], x);
}

void insert(int &u, int x, int y) {
    splay(u, x + 1); splay(ch[u][0], x);
    ch[ch[u][0]][1] = y; update(ch[u][0]); update(u);
}

ll ans;
void dfs(int u) {
    if(!u) return;
    pushdown(u);
    dfs(ch[u][0]);
    if(u <= 100000) ans += 1ll * val[u] * (val[u] - 1) / 2;
    dfs(ch[u][1]);
}

int main() {
    read(n);
    for(register int i = 1; i <= n; i++) read(a[i].h), read(a[i].gs);
    sort(a + 1, a + n + 1); int now = 1; root = 1;
    ch[root][0] = 100001; ch[root][1] = 100002;
    val[100001] = -1; val[100002] = 100002;
    update(100001); update(100002); update(root);
    for(register int i = 1; i <= n; i++) {
        while(now < a[i].h) {
            ++now; update(now);
            insert(root, 1, now);
        }
        splay(root, a[i].gs + 2); splay(ch[root][0], a[i].gs + 1);
        int left = find(ch[root][0], val[ch[root][0]]), v = val[ch[root][0]], l = ch[root][0];
        ch[root][0] = 0; update(root);
        int right = find(root, v + 1);
        if(!right) {
            add_tag(l, 1);
            ch[root][0] = l;
            update(root);
        } else {
            // fprintf(stderr, "left = %d\n", left);
            splay(l, left + 1);
            int ll = ch[l][0]; ch[l][0] = 0; update(l);
            add_tag(ll, 1); add_tag(l, 1);
            insert(root, right, l);
            splay(root, 1); ch[root][0] = ll; update(root);
        }
    }
    dfs(root);
    cout << ans << endl;
    return 0;
}

转载于:https://www.cnblogs.com/LJC00118/p/10462769.html

相关文章:

  • 乐视云计算被列入失信名单;三星华为达成和解;Python3 采用率超 84%丨Q新闻
  • django -- 修改admin 密码问题
  • Java 最常见的 200+ 面试题:面试必备
  • lvm管理卷之缩减卷大小
  • 使用WebShellKiller检查服务器后门文件
  • quasar-framework cnodejs社区
  • 前端面试必懂的 - http 网络知识
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • Grafana v6.0.1 发布,系统指标监控与分析平台
  • 兼容:获取浏览器滚动位置
  • 教你一招用 IDE 编程提升效率的骚操作!
  • fft相关的复习
  • 010-cloudboot批量安装rancheros
  • Audacity 2.3.1 发布,恢复 Linux 支持
  • 本地vs云:大数据厮杀的最终幸存者会是谁?
  • canvas 高仿 Apple Watch 表盘
  • CAP 一致性协议及应用解析
  • Python socket服务器端、客户端传送信息
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • V4L2视频输入框架概述
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • Vultr 教程目录
  • 京东美团研发面经
  • 聊聊sentinel的DegradeSlot
  • 前端工程化(Gulp、Webpack)-webpack
  • 容器服务kubernetes弹性伸缩高级用法
  • 算法之不定期更新(一)(2018-04-12)
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • 一、python与pycharm的安装
  • 一个JAVA程序员成长之路分享
  • Nginx实现动静分离
  • 交换综合实验一
  • $(function(){})与(function($){....})(jQuery)的区别
  • (C语言)球球大作战
  • (MATLAB)第五章-矩阵运算
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (待修改)PyG安装步骤
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (附源码)springboot 智能停车场系统 毕业设计065415
  • (附源码)ssm码农论坛 毕业设计 231126
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (转)大道至简,职场上做人做事做管理
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • .net core使用RPC方式进行高效的HTTP服务访问
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .net 怎么循环得到数组里的值_关于js数组
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • .NET版Word处理控件Aspose.words功能演示:在ASP.NET MVC中创建MS Word编辑器
  • .NET开发不可不知、不可不用的辅助类(一)
  • .NET连接数据库方式
  • .net流程开发平台的一些难点(1)
  • .pings勒索病毒的威胁:如何应对.pings勒索病毒的突袭?
  • /bin/rm: 参数列表过长"的解决办法