~~~题面~~~

题解:

  一开始翻网上题解看了好久都没看懂,感觉很多人都讲得不太详细,所以导致一些细节的地方看不懂,所以这里就写详细一点吧,如果有不对的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. spring-boot、mybatis整合

    一.MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以使用简单的 X ...

  2. 一 Hive安装及初体验

    一 .Hive安装及初体验 1 .hive简介 Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能. 1.1直接使用hadoop面临的问题 ...

  3. java 面向对象一

    一 基础部分 1.基本数据类型 Java的八种基本数据类型不支持面向对象的编程机制,不具备“对象”的特性:没有成员变量.方法可以调用.java之所以提供这八种基本数据类型,是为了照顾程序员的传统习惯. ...

  4. [USACO09Open] Tower of Hay 干草塔

    为了调整电灯亮度,贝西要用干草包堆出一座塔,然后爬到牛棚顶去把灯泡换掉.干草包会从传送带上运来,共会出现N包干草,第i包干草的宽度是W i ,高度和长度统一为1.干草塔要从底层开始铺建.贝西会选择最先 ...

  5. [JSON].getObj( keyPath )

    语法:[JSON].getObj( keyPath ) 返回:[JSON] 说明:返回指定键名路径的JSON对象,指定键名路径不存在时返回空的toJson对象(强烈建议使用 [JSON].exists ...

  6. mahout协同过滤算法各接口

    Mahout协同过滤算法 Mahout使用了Taste来提高协同过滤算法的实现,它是一个基于Java实现的可扩展的,高效的推荐引擎.Taste既实现了最基本的基于用户的和基于内容的推荐算法,同时也提供 ...

  7. Dev c++ 调试步骤

    不能调试的时候,修改下列地方: 1.在“工具”->编译选项->”Add following commands when calling complier”下面的编辑框里写入:-g3 2.在 ...

  8. Asp.net之数组应用

    string[] abc=new string[8]{"1","2","3","4","1",&qu ...

  9. SpringBoot在IntelliJ IDEA下for MAC 热加载

    说在前面 热加载:文件内容变更服务器自动运行最新代码.实则在IDEA环境进行热部署后,下述过程一气呵成. 1代码变更,文件自动保存(IDEA自动保存代码,用户无需使用COMMAND+SAVE快捷键): ...

  10. HDU 1569 方格取数(2)(最大流最小割の最大权独立集)

    Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大.   ...