BZOJ5249: [2018多省省队联测]IIIDX(线段树 贪心)
题意
Sol
不难发现题目给出的是一个树,其中\(\frac{i}{K}\)是\(i\)的父亲节点
首先,当\(d_i\)互不相同时,一个显然的贪心策略就是优先给编号小的分配较大的权值。可以排序后dfs完成。
但是,当\(d_i\)相同时,可能存在这样一种情况:把编号小的子树内权值较大的节点,和某个编号较大的根交换后,仍然满足要求
比如\(N = 4, K = 2, a = {1, 1, 1, 2}\)
此时直接贪心的话会输出\(1, 1, 1, 2\),实际上最优解为\(1, 1, 2, 1\)
这时候怎么办呢?
考虑一个节点\(p\)可以选择权值为\(x\)的条件是什么,因为该节点子树内的权值一定都比\(x\)大
因此对于每个权值小于\(x\)的数,权值比它大且可以选择的数至少为\(siz[p]\)个
同时根据贪心的策略,先遍历到的节点应该选大的权值。
这样就不难得到一个算法:
首先按权值从大到小排序,同时用线段树维护出每个位置权值比它大且能选择的位置个数
对于每个点\(p\),在线段树上二分出最大的满足条件的位置\(x\)。同时,当权值相同时,该位置应该更靠右。
然后再在区间\([x, n]\)中的所有点减去\(siz[x]\)
注意一个细节,当遍历到某个节点时,应该消去父亲对他的影响
写完代码 -> 过样例 -> 1A hhhhhh(虽然是抄的)
60分
#include<bits/stdc++.h>
#define sz(x) (int)x.size()
using namespace std;
const int MAXN = 5e5 + 10;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N; double K;
int a[MAXN], ans[MAXN], res;
vector<int> v[MAXN];
int AddEdge(int x, int y) {
v[x].push_back(y);
}
void dfs(int x) {
for(int i = 0; i < sz(v[x]); i++) dfs(v[x][i]);
if(x) ans[x] = a[res--];
}
int main() {
scanf("%d%lf", &N, &K); res = N;
//printf("%lf\n", K);
for(int i = 1; i <= N; i++) {
int pre = (int) floor(i / K);
a[i] = read(); AddEdge(pre, i);
}
sort(a + 1, a + N + 1);
dfs(0);
for(int i = 1; i <= N; i++) printf("%d ", ans[i]);
return 0;
}
AC代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5e5 + 10;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N; double K;
int cnt[MAXN], fa[MAXN], siz[MAXN], ans[MAXN], a[MAXN];
#define ls k << 1
#define rs k << 1 | 1
struct Node {
int l, r, f, mn;
}T[MAXN << 2];
void update(int k) {
T[k].mn = min(T[ls].mn, T[rs].mn);
}
void add(int k, int val) {
T[k].f += val; T[k].mn += val;
}
void pushdown(int k) {
if(!T[k].f) return ;
add(ls, T[k].f); add(rs, T[k].f);
T[k].f = 0;
}
void Build(int k, int ll, int rr) {
T[k] = (Node) {ll, rr, 0, 0};
if(ll == rr) {T[k].mn = ll; return ;}
int mid = ll + rr >> 1;
Build(ls, ll, mid); Build(rs, mid + 1, rr);
update(k);
}
void IntervalAdd(int k, int ll, int rr, int val) {
if(ll <= T[k].l && T[k].r <= rr) {add(k, val); return ;}
pushdown(k);
int mid = T[k].l + T[k].r >> 1;
if(ll <= mid) IntervalAdd(ls, ll, rr, val);
if(rr > mid) IntervalAdd(rs, ll, rr, val);
update(k);
}
int Query(int k, int sz) {
if(T[k].l == T[k].r) return T[k].mn >= sz ? T[k].l : T[k].l + 1;
pushdown(k);
if(T[rs].mn >= sz) return Query(ls, sz);
else return Query(rs, sz);
}
int main() {
N = read(); cin >> K;
for(int i = 1; i <= N; i++) {
a[i] = read();
int t = (int) floor(i / K); fa[i] = t; siz[i] = 1;
}
for(int i = N; i >= 0; i--) siz[fa[i]] += siz[i];
Build(1, 1, N);
sort(a + 1, a + N + 1, greater<int>());
for(int i = N - 1; i >= 1; i--) cnt[i] = (a[i] == a[i + 1] ? cnt[i + 1] + 1 : 0);
for(int i = 1; i <= N; i++) {
if(fa[i] && fa[i] != fa[i - 1]) IntervalAdd(1, ans[fa[i]], N, siz[fa[i]] - 1);
int t = Query(1, siz[i]); t += cnt[t]; cnt[t]++; t -= (cnt[t] - 1);
ans[i] = t;
IntervalAdd(1, t, N, -siz[i]);
}
for(int i = 1; i <= N; i++) printf("%d ", a[ans[i]]);
return 0;
}
BZOJ5249: [2018多省省队联测]IIIDX(线段树 贪心)的更多相关文章
- bzoj5249 [2018多省省队联测]IIIDX
转化一下问题变成给定一棵树,一个序列,求父亲的权值小于子树的最大方案. 直接贪心会在有重复权值时出现错误,我们考虑用线段树优化贪心. 将序列从小到大排序,线段树上每个点记录他和他右边当前还可用的权值, ...
- bzoj千题计划324:bzoj5249: [2018多省省队联测]IIIDX(线段树)
https://www.lydsy.com/JudgeOnline/problem.php?id=5249 把树建出来 如果所有的d互不相同,后续遍历即可 现在有的d相同 将d从小到大排序,考虑如何将 ...
- 5249: [2018多省省队联测]IIIDX
5249: [2018多省省队联测]IIIDX 链接 分析: 贪心. 将给定的权值从大到小排序,从第一个往后挨个赋值,考虑第i个位置可以赋值那些树.首先满足前面必须至少有siz[i]个权值没选,如果存 ...
- bzoj 5249 [2018多省省队联测] IIIDX
bzoj 5249 [2018多省省队联测] IIIDX Link Solution 首先想到贪心,直接按照从大到小的顺序在后序遍历上一个个填 但是这样会有大问题,就是有相同的数的时候,会使答案不优 ...
- BZOJ 5249: [2018多省省队联测]IIIDX(贪心 + 线段树)
题意 这一天,\(\mathrm{Konano}\) 接到了一个任务,他需要给正在制作中的游戏 \(\mathrm{<IIIDX>}\) 安排曲目 的解锁顺序.游戏内共有\(n\) 首曲目 ...
- 【刷题】BZOJ 5249 [2018多省省队联测]IIIDX
Description [题目背景] Osu听过没?那是Konano最喜欢的一款音乐游戏,而他的梦想就是有一天自己也能做个独特酷炫的音乐游戏.现在,他在世界知名游戏公司KONMAI内工作,离他的梦想也 ...
- bzoj5252 [2018多省省队联测]林克卡特树
斜率优化树形dp?? 我们先将问题转化成在树上选K+1条互不相交路径,使其权值和最大. 然后我们考虑60分的dp,直接维护每个点子树内选了几条路径,然后该点和0/1/2条路径相连 然后我们会发现最后的 ...
- bzoj 5252: [2018多省省队联测]林克卡特树
Description 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做& ...
- [九省联考2018] IIIDX 线段树+贪心
题目: 给出 k 和 n 个数,构造一个序列使得 d[i]>=d[i/k] ,并且字典序最大. 分析: 听说,当年省选的时候,这道题挡住了大批的高手,看上去十分简单,实际上那道弯段时间内是转不过 ...
随机推荐
- SDUT OJ 数据结构实验之排序一:一趟快排
数据结构实验之排序一:一趟快排 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem Descrip ...
- 3.mouseenter和mouseover事件的区别
<html> <head> <meta charset="UTF-8"> <script src="jquery-3.3.1.j ...
- bdd相关整理介绍
BDD介绍 什么是BDD Behavior-driven development In software engineering, behavior-driven development (BDD) ...
- (C/C++) Link List - C++ 版本
利用C++寫一個基本的 Link list 練習,功能包含 pint list.CreatList.Insert.Delete.Reverse.Search.Clear.GetLen. 先建立相關的C ...
- tornado 08 数据库-ORM-SQLAlchemy-表关系和简单登录注册
tornado 08 数据库-ORM-SQLAlchemy-表关系和简单登录注册 引言 #在数据库,所谓表关系,只是人为认为的添加上去的表与表之间的关系,只是逻辑上认为的关系,实际上数据库里面的表之间 ...
- P2468 [SDOI2010]粟粟的书架
传送门 二合一题.... 前面 $50$ 分: 考虑取书显然优先取厚的,所以答案满足单调性 发现 $P_{i,j}$ 不大,所以考虑二分最小厚度 $mid$,把大于等于 $mid$ 的书取走 维护 $ ...
- BZOJ - 2457 思維+貪心
//為什麼我的Chrome OS更新後變成強制繁體了?? 題目要求使用最少的雙端隊列來維護一個單調非降序列 先來看下規律 首先,val肯定是單調非降的,在相等val範圍內的id可以xjb亂放不影響 其 ...
- i2c设备驱动之设备地址
第一步:查找设备的数据手册可得到设备的从机地址.读写地址. 很不巧的是我在这里又卡了近一天,由于自己的硬件知识学得相当的那啥,哎,没办法,怨不得别人. 今天终于开窍了!!!!! 在开始条件(S)后,发 ...
- JS中||的某些用法
var a = 0 ||'sda';console.log(a);//sda var a = '' ||'sda';console.log(a);//sda
- nodejs下载器,通过chrome代理下载http资源
var config={ //不想访问的东西,节约流量 "404":[ "http://qidian.qpic.cn/qdbimg" ], //奇数为需要下载的 ...