题意

题目链接

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(线段树 贪心)的更多相关文章

  1. bzoj5249 [2018多省省队联测]IIIDX

    转化一下问题变成给定一棵树,一个序列,求父亲的权值小于子树的最大方案. 直接贪心会在有重复权值时出现错误,我们考虑用线段树优化贪心. 将序列从小到大排序,线段树上每个点记录他和他右边当前还可用的权值, ...

  2. bzoj千题计划324:bzoj5249: [2018多省省队联测]IIIDX(线段树)

    https://www.lydsy.com/JudgeOnline/problem.php?id=5249 把树建出来 如果所有的d互不相同,后续遍历即可 现在有的d相同 将d从小到大排序,考虑如何将 ...

  3. 5249: [2018多省省队联测]IIIDX

    5249: [2018多省省队联测]IIIDX 链接 分析: 贪心. 将给定的权值从大到小排序,从第一个往后挨个赋值,考虑第i个位置可以赋值那些树.首先满足前面必须至少有siz[i]个权值没选,如果存 ...

  4. bzoj 5249 [2018多省省队联测] IIIDX

    bzoj 5249 [2018多省省队联测] IIIDX Link Solution 首先想到贪心,直接按照从大到小的顺序在后序遍历上一个个填 但是这样会有大问题,就是有相同的数的时候,会使答案不优 ...

  5. BZOJ 5249: [2018多省省队联测]IIIDX(贪心 + 线段树)

    题意 这一天,\(\mathrm{Konano}\) 接到了一个任务,他需要给正在制作中的游戏 \(\mathrm{<IIIDX>}\) 安排曲目 的解锁顺序.游戏内共有\(n\) 首曲目 ...

  6. 【刷题】BZOJ 5249 [2018多省省队联测]IIIDX

    Description [题目背景] Osu听过没?那是Konano最喜欢的一款音乐游戏,而他的梦想就是有一天自己也能做个独特酷炫的音乐游戏.现在,他在世界知名游戏公司KONMAI内工作,离他的梦想也 ...

  7. bzoj5252 [2018多省省队联测]林克卡特树

    斜率优化树形dp?? 我们先将问题转化成在树上选K+1条互不相交路径,使其权值和最大. 然后我们考虑60分的dp,直接维护每个点子树内选了几条路径,然后该点和0/1/2条路径相连 然后我们会发现最后的 ...

  8. bzoj 5252: [2018多省省队联测]林克卡特树

    Description 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做& ...

  9. [九省联考2018] IIIDX 线段树+贪心

    题目: 给出 k 和 n 个数,构造一个序列使得 d[i]>=d[i/k] ,并且字典序最大. 分析: 听说,当年省选的时候,这道题挡住了大批的高手,看上去十分简单,实际上那道弯段时间内是转不过 ...

随机推荐

  1. WPF:CheckBox竖向的滑块效果

    原文:WPF:CheckBox竖向的滑块效果 之前做了一个横向的滑块效果,<WPF:CheckBox滑块效果>,其实我觉得那个不好看,今天又做了一个竖向的玩. <Style Targ ...

  2. Spring学习笔记(一)—— Spring介绍及入门案例

    一.Spring概述 1.1 Spring是什么 Spring是一个开源框架,是于2003年兴起的一个轻量级的Java开发框架, 由Rod Johnson 在其著作<Expert one on ...

  3. node.js express 启用 https

    服务端和客户端各有一对公钥和私钥,使用公钥加密的数据只能用私钥解密,建立https传输之前,客户端和服务端互换公钥.客户端发送数据前使用服务端公钥加密,服务端接收到数据后使用私钥解密,反之亦如此. 公 ...

  4. vcftools安装与使用

    官网地址:https://vcftools.github.io/examples.html vcftools的软件下载:https://vcftools.github.io/examples.html ...

  5. ssm框架的搭建流程

    1.新建一个Maven project (1)选中create a simple project,自动配置必要的文件 (2)Packaging选择war类型.jar和war的区别就是一个是普通的jav ...

  6. vue修改组件样式

    .el-date-editor /deep/ input{ padding-left:30px; } 改变引入的组件里面元素的样式: 1.去掉css内的scoped,但是这样会污染全局 2.加上/de ...

  7. [转] 运维小技巧:使用ss命令代替 netstat,和netstat说再见

    [From] https://blog.csdn.net/fenglailea/article/details/51810977 ss是Socket Statistics的缩写. 顾名思义,ss命令可 ...

  8. 微信小程序实现图片上传功能

    前端: 微信开发者工具 后端:.Net 服务器:阿里云 这里介绍微信小程序如何实现上传图片到自己的服务器上 前端代码 data: { productInfo: {} }, //添加Banner bin ...

  9. Unity 代码控制游戏对象是父物体的第多少个子对象

    一个canvas下的游戏对象,排列顺序越往下,渲染顺序就越靠后,就会覆盖在先前的图形上.也就是说,运行游戏后,物体的渲染顺序是一个一个计算的. Transform.SetSiblingIndex(in ...

  10. android 学习资源网址

    脚本之家: http://www.jb51.net/list/list_233_2.htm csdn: http://blog.csdn.net/xubo578/article/details/571 ...