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;
}
luoguP4647 [IOI2007] sails 船帆的更多相关文章
- [IOI2007] sails 船帆
显然答案与杆的顺序无关(按每个高度考虑). 从高到低考虑杆,设此时的状态为\(S\),\(S[i]\)是高度\(i\)的帆的数目,初始全为\(0\),当前杆的高度为\(h\),杆上需要放置的帆的数目为 ...
- BZOJ1805[Ioi2007]Sail船帆——线段树+贪心
题目描述 让我们来建造一艘新的海盗船.船上有 N个旗杆,每根旗杆被分成单位长度的小节.旗杆的长度等于它被分成的小节的数目.每根旗杆上会挂一些帆,每张帆正好占据旗杆上的一个小节.在一根旗杆上的帆可以任意 ...
- BZOJ.1805.[IOI2007]sail船帆(贪心 线段树)
BZOJ 洛谷 首先旗杆的顺序没有影响,答案之和在某一高度帆的总数有关.所以先把旗杆按高度排序. 设高度为\(i\)的帆有\(s_i\)个,那么答案是\(\sum\frac{s_i(s_i-1)}{2 ...
- bzoj1805: [Ioi2007]Sail 船帆
可以发现旗杆的顺序是没有用的,对于每列,它的答案是它的最大值mx*(mx+1)/2 高度由小到大排序旗杆,问题可以转化为在前h行选k个最小的值 考虑激情splay乱搞(我只会splay......) ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- 通过sails和阿里大于实现短信验证
通过sails与阿里大于来实现注册短信验证码的发送,逻辑图如下 1.用户在客户端发送手机号给服务器,服务器接收到手机号,生成对应时间戳,随机四位数验证码 2.服务器将电话号码和验证码告诉阿里大于服务器 ...
- Node.js之sails框架
先开一坑,有空更新,记录最近钉钉项目上对node及sails框架的学习记录和理解
- Node.js~sails.js~package.json的作用
回到目录 我们在sails框架进行node.js开发时,会涉及到项目的迁移,当迁移后可能你的module即丢失,这时,希望快速的安装所有的包包,可以使用下面命令 1 cd 你当前的sails项目 2 ...
- Node.js与Sails~项目结构与Mvc实现
回到目录 Sails是一个Node.js的中间件架构,帮助我们很方便的构建WEB应用程序,网址:http://www.sailsjs.org/,它主要是在Express框架的基础上发展起来的,扩展了新 ...
随机推荐
- 迷你MVVM框架 avalonjs 0.96发布
本版本主要是性能优化与 fix BUG,改进如下: 处理notifySubscribers中的BUG,它在标准浏览器不会移除那些无用的视图刷新函数.详见这里 重构modelBindling.SELEC ...
- java web作用域page request session application
转载自:http://blog.csdn.net/wyd458549392147/article/details/6944481 1.page指当前页面.只在一个jsp页面里有效 . 2.reques ...
- 03-使用html静态页面展示执行效果
使用工作流框架可以做什么事情?写代码呗,没那么简单.
- (K)ubuntu上将分区格式化成NTFS格式
新买了硬盘,装系统时,为Windows预留了几个分区,由于没有其他选择,因此将分区格式化成了fat32格式.装完系统后,总是很纠结,想把这些分区格式化成NTFS格式. google了一下,从这个网址( ...
- ubuntu下安装最新的nodejs
# apt-get update # apt-get install -y python-software-properties software-properties-common # add-ap ...
- JAVA里的CAS算法简析
Atomic 从JDK5开始, java.util.concurrent包里提供了很多面向并发编程的类. 使用这些类在多核CPU的机器上会有比较好的性能.主要原因是这些类里面大多使用(失败-重试方式的 ...
- Linux TCP拥塞控制算法原理解析
这里只是简单梳理TCP各版本的控制原理,对于基本的变量定义,可以参考以下链接: TCP基本拥塞控制http://blog.csdn.net/sicofield/article/details/9708 ...
- [Jenkins]执行SoapUI脚本,怎样在邮件内容里面嵌入html
在Editable Email Notification的Default Content里面加入这样一段: ${FILE,path="result-output/overview-summa ...
- W-D-S-Nandflash
1.6410的硬件一上电就会把nandflash前8K的内容拷贝到6410片内内存来,从片内内存0地址开始运行,如果烧写到nandflash里面的程序大于8k,则拷贝到6410片内的8k程序要把nan ...
- 【转载】【JAVA秒会技术之图片上传】基于Nginx及FastDFS,完成图片的上传及展示
基于Nginx及FastDFS,完成商品图片的上传及展示 一.传统图片存储及展示方式 存在问题: 1)大并发量上传访问图片时,需要对web应用做负载均衡,但是会存在图片共享问题 2)web应用服务器的 ...