题意

题目链接

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. php常用的系统函数大全

    字符串函数 strlen:获取字符串长度,字节长度 substr_count 某字符串出现的次数 substr:字符串截取,获取字符串(按照字节进行截取) mb_strlenmb_substr str ...

  2. jenkins安装maven工具

    下载maven工具,然后解压到/usr/local下面 然后在jenkins上面添加maven工具.指定他的设置配置文件(全局) 指定maven的目录位置 应用保存即可 !!! 虽然maven安装简单 ...

  3. javascrip 词法分析详解

      JavaScript的高级知识---词法分析 词法分析 词法分析方法: js运行前有一个类似编译的过程即词法分析,词法分析主要有三个步骤: 分析参数 再分析变量的声明 分析函数说明 函数在运行的瞬 ...

  4. flask总结03

    一:flask的请求勾子 01:钩子概念说明: 在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如: 在请求开始时,建立数据库连接: 在请求开始时,根据需求进行权限校验: 在请求结束时 ...

  5. [转] JavaScript控制浏览器全屏及各种浏览器全屏模式的方法、属性和事件

    [From] http://www.jb51.net/article/76695.htm HTML 5中的full screen,目前可以在除IE和opera外的浏览器中使用 ,有的时候用来做全屏AP ...

  6. spring4.x hibernate4.x 整合 ehcache 注解 annotate

    [From] http://my.oschina.net/alexgaoyh/blog/348188

  7. fopen\fread\fwrite\fseed函数的使用

    使用 <stdio.h> 头文件中的 fopen() 函数即可打开文件,它的用法为: FILE *fopen(char *filename, char *mode); filename为文 ...

  8. Android so 库按需打包

    Fresco 大部分的代码是由Java写的,但是里面也有很多C++的代码.C++代码必须根据Android 设备的CPU类型(通常称为”ABIs”)进行编译.目前Fresco支持五种 ABI: arm ...

  9. Nginx + Lua搭建文件上传下载服务

    收录待用,修改转载已取得腾讯云授权 最新腾讯云技术公开课直播,提问腾讯W3C代表,如何从小白成为技术专家?点击了解活动详情 作者 | 庄进发 编辑 | 迷鹿 庄进发,信息安全部后台开发工程师,主要负责 ...

  10. hcheck 脚本

    hcheck.sql - Script to Check for Known Problems in Oracle8i, Oracle9i, Oracle10g, Oracle 11g and Ora ...