~~~题面~~~

题解:

  一开始翻网上题解看了好久都没看懂,感觉很多人都讲得不太详细,所以导致一些细节的地方看不懂,所以这里就写详细一点吧,如果有不对的or不懂的可以发评论在下面。

  首先有一个比较明显的50分贪心:

  先把d排好序,然后按从小到大的顺序贪心的给每个点选值,同等条件下优先编号大的,于是越小的值会越趋近于放在编号越大的上面。

  但是这样在数字重复的情况下是不对的, 比如下面这组数据:

  4 3.0

  1 1 2 2

  贪心会得到1 1 2 2 ,而正确答案是1 2 2 1.

  因此换个角度考虑,在什么情况下一个点可以取到一个值x?

  设这个点的子树大小为Size[i],那么这个点可以取到值x,当且仅当大于等于x的还没被取的值的个数 >= Size[i],原因应该是很好理解的,毕竟还要有Size[i] - 1和比x大的值放在i的子树上才行。

  因此我们先对d从小到大排序去重,统计每个值的出现次数cnt[x], 然后对于每个数统计一个f[x]表示大于等于x的还没被取的值的个数为f[x].

  

  假设我们给节点i匹配上了一个值x,那么这个策决策对小于等于x的值的影响是确定的,因此将所有小于等于x的值的f数组都减小SIze[i],表示这些值的右边可以取的值又减小了Size[i]个。

  我们将和这个操作称为“预定”,因为我们现在并不知道点i的子树分别会选择哪些值,但我们知道它们要选几个值,所以我们相当于先告诉后面的人,这个节点i已经坐到了x这个值上,并且要求后面的人为它的子树留Size[i] - 1个座位。

  因为这个决策对大于x的值的影响是不确定的,我们暂时没有修改它,但其实这个决策会对它产生影响,那么对于一个值k,在取它之前的决策到底对它产生了什么样的影响呢?

  对于一个值k,它的真正的f[k]其实是min(f[1], f[2], f[3] ....f[k]),因为每个f值都相当于一个后缀和,一个合法的值不能使得f[k]反而比它前面的f值更大,因为前面的f值要比f[k]统计了更多的数。

  

  因为题目要求使得字典序最大,所以我们按照编号从小到大给节点分配值显然是最优的。

  因此我们每次就是要在剩下的数上寻找一个最靠右的,并且使得min(f[1], f[2], f[3] ...f[k]) >= Size[i]的k。

  因为涉及区间修改和查询,我们使用线段树来维护所有的f值,每次选好一个值,我们就把一些已经确定的影响从线段树中删除(对一个区间进行- Size[i]的操作)。

  对于每次选值,我们都可以在线段树上进行二分来查找满足上述粗体字要求的最靠右的值。

  值得注意的是,在每次查询前,如果一个节点的父亲的影响还没有被撤销的话,应该要撤销它父亲的影响。(即把父亲给子树占的座给加回来 :1 ~ 父亲匹配值的f值 加上 Size[fa] - 1)

  为什么呢?

  想象一下,如果不撤销父亲的影响的话,岂不是相当于别人特意给你占了座,结果你自己还不能坐上去?

  因为一个节点的儿子都是连续的,所以我们在撤销的父亲的影响后,会马上把不应该撤销的部分给补上(儿子的子树在不断的加上来),所以不用担心对之后的决策造成影响。

  

 #include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 551000
#define ac 2500000 int n, w, go, tot, rnt;
double k;
int ans[AC], cnt[AC], father[AC], Size[AC], f[AC], s[AC];//cnt[i]表示排名第i位的d值出现的次数
bool done[AC]; inline int read()
{
int x = ;char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} inline int Min(int a, int b){
return a > b ? b : a;
} struct seg_tree{
int tree[ac], lazy[ac], l[ac], r[ac]; inline void update(int x){
tree[x] = Min(tree[x * ], tree[x * + ]);
} inline void pushdown(int x)
{
if(lazy[x])
{
int ll = x * , rr = ll + ;
tree[ll] += lazy[x], tree[rr] += lazy[x];
lazy[ll] += lazy[x], lazy[rr] += lazy[x];
lazy[x] = ;
}
} void build(int x, int ll, int rr)
{
l[x] = ll, r[x] = rr;
if(ll == rr){tree[x] = f[ll]; return ;}
int mid = (ll + rr) >> ;
build(x * , ll, mid), build(x * + , mid + , rr);
update(x);
} void change(int x, int ll, int rr)
{
pushdown(x);
if(l[x] == ll && r[x] == rr)
{
tree[x] += w, lazy[x] += w;
return ;
}
int mid = (l[x] + r[x]) >> ;
if(rr <= mid) change(x * , ll, rr);
else if(ll > mid) change(x * + , ll, rr);
else change(x * , ll, mid), change(x * + , mid + , rr);
update(x);
} void find(int x)
{
pushdown(x);
if(l[x] == r[x]){go = tree[x] >= w ? l[x] : l[x] - ; return ;}
if(tree[x * ] >= w) find(x * + );
else find(x * );
update(x);
}
}T; void pre()
{
n = read(), scanf("%lf", &k);
for(R i = ; i <= n; i ++) s[i] = read(), Size[i] = ;
sort(s + , s + n + );
for(R i = ; i <= n; i ++)
{
++ cnt[tot + ];
if(s[i] != s[i + ]) s[++tot] = s[i];
}
for(R i = tot; i; i --)
f[i] = f[i + ] + cnt[i];//存下每个值右边有多少个可供选择的值
for(R i = n; i; i --)
father[i] = floor(i / k), Size[father[i]] += Size[i];//获取每个节点的Size
T.build(, , tot);
} void work()
{
for(R i = ; i <= n; i ++)
{
int fa = floor(i / k);
if(fa && !done[fa]) w = Size[fa] - , T.change(, , ans[fa]);//如果有父亲的话,要先把给儿子预定的节点还回来以帮助正确判断
w = Size[i], done[fa] = true;
T.find(), w = -Size[i];//先找到一个合法的点
T.change(, , go);//再减去已经被预定的位置
ans[i] = go;
printf("%d ", s[go]);
}
printf("\n");
} int main()
{
// freopen("in.in", "r", stdin);
pre();
work();
// fclose(stdin);
return ;
}

  

[九省联考2018]IIIDX 贪心 线段树的更多相关文章

  1. BZOJ.5249.[九省联考2018]iiidx(贪心 线段树)

    BZOJ LOJ 洛谷 \(d_i\)不同就不用说了,建出树来\(DFS\)一遍. 对于\(d_i\)不同的情况: Solution 1: xxy tql! 考虑如何把这些数依次填到树里. 首先对于已 ...

  2. 洛谷P4364 [九省联考2018]IIIDX 【线段树】

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

  3. [BZOJ5249][九省联考2018]IIIDX:线段树+贪心

    分析 GXZlegend orz 构造出一组合法的解并不是难事,但是我们需要输出的是字典序最大的解. 字典序最大有另一种理解方式,就是让越小的数尽量越靠后. 我们从树的根结点出发,从1开始填数,构造出 ...

  4. 洛谷P4364 [九省联考2018]IIIDX(线段树)

    传送门 题解看得……很……迷? 因为取完一个数后,它的子树中只能取权值小于等于它的数.我们先把权值从大到小排序,然后记$a_i$为他左边(包括自己)所有取完他还能取的数的个数.那么当取完一个点$x$的 ...

  5. [luogu] P4364 [九省联考2018]IIIDX(贪心)

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

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

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

  7. [九省联考2018]IIIDX

    题目描述 这一天,Konano接到了一个任务,他需要给正在制作中的游戏<IIIDX>安排曲目的解锁顺序.游戏内共有n首曲目 ,每首曲目都会有一个难度d,游戏内第i首曲目会在玩家Pass第t ...

  8. BZOJ5249:[九省联考2018]IIIDX——题解

    https://www.luogu.org/problemnew/show/P4364#sub https://www.lydsy.com/JudgeOnline/problem.php?id=524 ...

  9. [luogu]P4364 [九省联考2018]IIIDX

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

随机推荐

  1. Windows 显示环境变量

    echo %% D:\>echo %python3% C:\Users\zy\AppData\Local\Programs\Python\Python36 D:\> 我的环境变量如下:

  2. springBoot Swagger2 接口文档生成

    // 生成配置类 package com.irm.jd.config.swagger; import org.springframework.context.annotation.Bean; impo ...

  3. Drupal 出错的解决办法

    今天安装了superfish菜单模块,安装了一个新菜单后.网站突然打不开了.空白! 第一反应看日志,Apache服务器日志没有发现异常. 可以肯定是添加菜单时,在ATTACH BLOCK部分的区块区域 ...

  4. iOS 测试工具reveal可视化调试工具的使用

    简单翻译一下reveal可视化图形工具插入项目的官方文档(官方英文版file:///Applications/Reveal.app/Contents/SharedSupport/Documentati ...

  5. 对JSON的理解

    JSON语法: JSON是一种结构化数据,它是一种数据格式 JSON可以概括为三种类型:简单值.对象.数组 注意:JSON不支持变量.函数和对象实例 一.JSON简单值 包括字符串.数值.布尔值.和n ...

  6. leetcode-打家劫舍(动态规划)

    你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给定一个代表每 ...

  7. [Clr via C#读书笔记]Cp6类型和成员基础

    Cp6类型和成员基础 成员 常量:字段(静态字段和实例字段):实例构造器:类型构造器(用于静态字段的构造):方法(静态方法和实例方法):操作符重载(本质是一个方法):转换操作符:属性(本质还是方法): ...

  8. Scala学习笔记之Actor多线程与线程通信的简单例子

    题目:通过子线程读取每个文件,并统计单词数,将单词数返回给主线程相加得出总单词数 package review import scala.actors.{Actor, Future} import s ...

  9. 查看python中包的文档

    核心命令:python -m pydoc 查询某包:python -m pydoc 包名 示例: C:\Users\xxx>python -m pydoc pydoc - the Python ...

  10. VBS简明教程

    VBS简明教程   一.输出 VBS的输出使用函数Msgbox调用对话框进行输出. Msgbox(message) Message为要输出的信息 二.输入 VBS的输入,调用函数Inputbox()进 ...