显然答案与杆的顺序无关(按每个高度考虑)。

从高到低考虑杆,设此时的状态为\(S\),\(S[i]\)是高度\(i\)的帆的数目,初始全为\(0\),当前杆的高度为\(h\),杆上需要放置的帆的数目为\(k\),贪心地,假设两个高度的同等宜选,优先选择更高的;帆尽量放置在\(S[i]=0(i\le h)\)的高度上,若还有剩余,设剩下\(t(t\le k)\)个,则放置在除去以选择的高度以外,\(S[i](i\le h)\)前\(t\)小的位置。

整理一下,每次选出\(S[1\cdots h]\)中前\(k\)小的(相同大小选下标较大的)高度放置帆。

{5,3} 0 0 1 1 1  +0
{4,3} 1 1 2 1 1 +1
{4,1} 1 2 2 1 1 +1
{3,2} 2 2 3 1 1 +3
{3,2} 3 3 3 1 1 +4
{2,1} 3 4 3 1 1 +3

但是此时\(S\)似乎不好维护。。考虑将过程倒过来,从低到高考虑杆,(\(S\)一开始为空集,其余定义相同),假设两个高度同等宜选,优先选择更低的,其余大致相同。即每次选出\(S[1\cdots h]\)中前\(k\)小的(相同大小选下标较小的)高度放置帆。

{2,1} 1 0        +0
{3,2} 1 1 1 +0
{3,2} 2 2 1 +2
{4,1} 2 2 1 1 +0
{4,3} 3 2 2 2 +4
{5,3} 3 3 3 2 1 +4

这样用平衡树维护\(S\)(初始大小为0,每次长度变化时补0节点),每次查询全局前\(k\)小然后整体加一即可。(省去了下标范围的约束)。进一步可发现,连下标都不用维护了


巧妙的分割线(之前的splay已经弃坑了)

观察各个时态的\(S\),发现它总是一个单调不增的序列,把某时态的\(S\)中相同且相邻分成一块,如图,蓝色方框表示将选出前\(k\)小的位置,注意被完全覆盖的块的高度可以直接区间+1,而割开的块区间+1的范围是反过来的,显然这样的块最多一块,于是可以上线段树来维护。

答案也不用每步累加,设\(S[i]\)表示最终状态上高度为\(i\)的帆的数目,显然总答案是\(\sum_i\frac{S[i](S[i]-1)}2\),这与因为从本文第一句照应。

#include <bits/stdc++.h>
#define LL long long
const int N=1e5+10; namespace sgt {
struct sgtNode {
int mx,mn,add;
} t[N<<2];
#define ls (x<<1)
#define rs (x<<1|1)
void update(int x) {
t[x].mx=std::max(t[ls].mx,t[rs].mx);
t[x].mn=std::min(t[ls].mn,t[rs].mn);
}
void pushr(int x,int add) {t[x].mn+=add,t[x].mx+=add,t[x].add+=add;}
void pushdown(int x) {
if(t[x].add) pushr(ls,t[x].add),pushr(rs,t[x].add),t[x].add=0;
}
LL calc(int x,int l,int r) {
if(l==r) return 1LL*t[x].mx*(t[x].mx-1)/2;
int mid=(l+r)>>1; pushdown(x);
return calc(ls,l,mid)+calc(rs,mid+1,r);
}
void build(int x,int l,int r) {
t[x].mn=+1e9,t[x].mx=-1e9;
if(l==r) return; int mid=(l+r)>>1;
build(ls,l,mid); build(rs,mid+1,r);
}
void insert(int x,int l,int r,int p) {
if(l==r) return void(t[x].mx=t[x].mn=0);
int mid=(l+r)>>1; pushdown(x);
if(p<=mid) insert(ls,l,mid,p);
else insert(rs,mid+1,r,p);
update(x);
}
void modify(int x,int l,int r,int L,int R) {
if(L>R) return;
if(L<=l&&r<=R) return pushr(x,1);
int mid=(l+r)>>1; pushdown(x);
if(L<=mid) modify(ls,l,mid,L,R);
if(mid<R) modify(rs,mid+1,r,L,R);
update(x);
}
int getVal(int x,int l,int r,int p) {
if(t[x].mn==t[x].mx) return t[x].mn;
int mid=(l+r)>>1; pushdown(x);
if(p<=mid) return getVal(ls,l,mid,p);
else return getVal(rs,mid+1,r,p);
}
int getRangeL(int x,int l,int r,int w) {
if(l==r) return l;
int mid=(l+r)>>1; pushdown(x);
if(t[ls].mn<=w) return getRangeL(ls,l,mid,w);
else return getRangeL(rs,mid+1,r,w);
}
int getRangeR(int x,int l,int r,int w) {
if(l==r) return l;
int mid=(l+r)>>1; pushdown(x);
if(t[rs].mx>=w) return getRangeR(rs,mid+1,r,w);
else return getRangeR(ls,l,mid,w);
}
} int n,m;
std::pair<int,int> a[N]; int main() {
scanf("%d",&n);
for(int i=1; i<=n; ++i) {
scanf("%d%d",&a[i].first,&a[i].second);
m=std::max(m,a[i].first);
}
std::sort(a+1,a+n+1);
sgt::build(1,1,m);
for(int i=1,R=0; i<=n; ++i) {
while(R<a[i].first) sgt::insert(1,1,m,++R);
int pos=R-a[i].second+1; //被割开的位置
int val=sgt::getVal(1,1,m,pos);
int rgl=sgt::getRangeL(1,1,m,val);
int rgr=sgt::getRangeR(1,1,m,val); // std::cout<<val<<' '<<rgl<<' '<<rgr<<std::endl; sgt::modify(1,1,m,rgr+1,R);
sgt::modify(1,1,m,rgl,rgl+a[i].second-(R-rgr)-1);
}
printf("%lld\n",sgt::calc(1,1,m));
return 0;
}

[IOI2007] sails 船帆的更多相关文章

  1. luoguP4647 [IOI2007] sails 船帆

    https://www.luogu.org/problemnew/show/P4647 首先发现答案与顺序无关,令 $ x_i $ 表示高度为 $ i $ 的那一行帆的个数,第 $ i $ 行对答案的 ...

  2. BZOJ1805[Ioi2007]Sail船帆——线段树+贪心

    题目描述 让我们来建造一艘新的海盗船.船上有 N个旗杆,每根旗杆被分成单位长度的小节.旗杆的长度等于它被分成的小节的数目.每根旗杆上会挂一些帆,每张帆正好占据旗杆上的一个小节.在一根旗杆上的帆可以任意 ...

  3. BZOJ.1805.[IOI2007]sail船帆(贪心 线段树)

    BZOJ 洛谷 首先旗杆的顺序没有影响,答案之和在某一高度帆的总数有关.所以先把旗杆按高度排序. 设高度为\(i\)的帆有\(s_i\)个,那么答案是\(\sum\frac{s_i(s_i-1)}{2 ...

  4. bzoj1805: [Ioi2007]Sail 船帆

    可以发现旗杆的顺序是没有用的,对于每列,它的答案是它的最大值mx*(mx+1)/2 高度由小到大排序旗杆,问题可以转化为在前h行选k个最小的值 考虑激情splay乱搞(我只会splay......) ...

  5. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  6. 通过sails和阿里大于实现短信验证

    通过sails与阿里大于来实现注册短信验证码的发送,逻辑图如下 1.用户在客户端发送手机号给服务器,服务器接收到手机号,生成对应时间戳,随机四位数验证码 2.服务器将电话号码和验证码告诉阿里大于服务器 ...

  7. Node.js之sails框架

    先开一坑,有空更新,记录最近钉钉项目上对node及sails框架的学习记录和理解

  8. Node.js~sails.js~package.json的作用

    回到目录 我们在sails框架进行node.js开发时,会涉及到项目的迁移,当迁移后可能你的module即丢失,这时,希望快速的安装所有的包包,可以使用下面命令 1 cd 你当前的sails项目 2 ...

  9. Node.js与Sails~项目结构与Mvc实现

    回到目录 Sails是一个Node.js的中间件架构,帮助我们很方便的构建WEB应用程序,网址:http://www.sailsjs.org/,它主要是在Express框架的基础上发展起来的,扩展了新 ...

随机推荐

  1. UOJ#440. 【NOIP2018】填数游戏 动态规划

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ440.html 前言 菜鸡选手到省选了才做联赛题. 题解 首先我们分析一下性质: 1. 假如一个格子是 0,那么它的右上角 ...

  2. adb deviecs时显示的emulator-5554如何删除

    https://zhidao.baidu.com/question/548320666.html

  3. Hadoop优化

    一.影响MR程序效率的因素 1.计算机性能: CPU.内存.磁盘.网络, 计算机的性能会影响MR程序的速度与效率 2.I/O方面 1)数据倾斜(代码优化) 2)map和reduce数量设置不合理(通过 ...

  4. Alpha冲刺(5/10)——2019.4.27

    作业描述 课程 软件工程1916|W(福州大学) 团队名称 修!咻咻! 作业要求 项目Alpha冲刺(团队) 团队目标 切实可行的计算机协会维修预约平台 开发工具 Eclipse 团队信息 队员学号 ...

  5. tp5 整合 个推

    这里因为业务需要使用推送功能 uni 里面前端集成了个推 所以选择了个推来做推送. 个推的官方文档地址: http://docs.getui.com/getui/server/php/start/ 在 ...

  6. 使用ant编译zookeeper源码

    1. 安装Ant Ant下载地址:http://ant.apache.org/bindownload.cgi 解压即可. 注意如果不配置环境变量的话需要使用绝对路径,我配置了. 开始我ant跑错了 U ...

  7. npm几个常用命令

    npm install xxx 安装模块(例如npm install express 就会默认安装express的最新版本,也可以通过在后面加版本号的方式安装指定版本,如npm install exp ...

  8. TCP协议中是如何保证报文可靠传输的

    1.什么是TCP的可靠传输 它向应用层提供的数据是无差错的.有序的.无丢失的,换言之就是:TCP最终递交给应用层的数据和发送者发送的数据是一模一样的. 2.TCP保证可靠传输的办法有哪些? TCP采用 ...

  9. python函数用法

    一.定义函数 形参:函数完成一项工作所需要的信息,在函数定义时完成 实参:调用函数时传递给函数的信息 二.传递实参 1.位置实参:每个实参都关联到函数定义中的一个形参 示例: def describe ...

  10. date函数的属性

    date () a: "am"或是"pm" A: "AM"或是"PM" d: 几日,两位数字,若不足则补零:从" ...