题目:

  给出 k 和 n 个数,构造一个序列使得 d[i]>=d[i/k] ,并且字典序最大。

分析:

  听说,当年省选的时候,这道题挡住了大批的高手,看上去十分简单,实际上那道弯段时间内是转不过来的。

  首先,一个套路是,将这个序列的关系抽象成一棵树,i的父亲是floor(i/k),我们要要求子树内部的点的权值都比父亲大。

  我们观察子任务的特殊限制,di不一样?

  我们想,把原序列从大到小排序,在树上dfs给点赋值,在给一个点赋值时,要在序列上预留出siz[这棵子树]的位置,用来给子树内部的点赋值(排序就是为了方便在序列上预留位置)。

  但是,如果有重复的元素就办不了了,比如n=4, k=2 序列是1,1,1,2.

  排好应该是1 1 2 1,但是我们上面的方法会排成1 1 1 2

  为什么呢?

  我们从大到小排序,应该得到2 1 1 1.我们递归,首先是树根节点,需要预留4个位置,所以肯定要选最后一个(1),然后递归到第一个子树(序号为2),size为2,需要在这个子树留两个位置,所以我们把第二个1给了序号2这个位置,然后那个2就给了它的儿子(序号4)但是实际上,我们可以给它留一个1,把这个4给位置3.

  我这么分析会很乱,但是我们于情于理考虑一下,我们解决完了位置2,若想字典序最大,我们应该先最大化3这个位置。

  所以我们应该在给序号2找到最大值之后,应该为他的子树预留一些值,使这些值在合法的基础上尽可能小。

  所以我们应该排序后,建立一个序列c,c[i]的值代表排好序的序列上,i及i左边的所有值还剩下多少个可以选的。

  (序列c一开始肯定是1,2,3,4,5……)

  然后我们每次为一个点赋值,应该找到最靠左的一个位置i,使所有j>=i满足c[j]>=siz[这个点的子树]。

  并且选完之后,要找到这个位置往右最右边和他值相等的那个位置(前提是没有被用过的)。

  然后,用区间减法计算贡献,之后接着处理这个点的兄弟节点,没有了兄弟节点之后在进入某个点的子节点。

  进入一个子节点时,要将之前预留的位置(区间减去的数值)加回来,但是已经分配出去的(父亲的)权值就不要加回来了。

  所以是siz-1

代码:

 #include<bits/stdc++.h>
#define db double
using namespace std;
const int N=,inf=1e9;
struct segtree{
int l,r,ls,rs,mn,lz;
}t[N*];int a[N],b[N],ans[N],m,rt;
db k;int n,siz[N],fa[N],cnt[N],o=;
bool cmp(int u,int v){return u>v;}
void pushup(int cur){
int ls=t[cur].ls,rs=t[cur].rs;
t[cur].l=t[ls].l;t[cur].r=t[rs].r;
t[cur].mn=min(t[ls].mn,t[rs].mn);
} void pushdown(int cur){
int ls=t[cur].ls,rs=t[cur].rs,d=t[cur].lz;
t[ls].mn+=d;t[ls].lz+=d;
t[rs].mn+=d;t[rs].lz+=d;
t[cur].lz=;return ;
} void build(int x,int l,int r){
if(l==r){
t[x].l=t[x].r=l;t[x].ls=t[x].rs=-;
t[x].mn=l;return ;
} int mid=l+r>>;
t[x].ls=o++;t[x].rs=o++;
build(t[x].ls,l,mid);build(t[x].rs,mid+,r);
pushup(x);return ;
} void update(int x,int l,int r,int c){
if(l<=t[x].l&&t[x].r<=r)
{t[x].mn+=c;t[x].lz+=c;return ;}
pushdown(x);int mid=t[x].l+t[x].r>>;
if(l<=mid) update(t[x].ls,l,r,c);
if(mid<r) update(t[x].rs,l,r,c);
pushup(x);return ;
} int query(int x,int p){
if(t[x].l==t[x].r)
return t[x].mn>=p?t[x].l:t[x].l+;
pushdown(x);int mid=t[x].l+t[x].r>>;
if(p<=t[t[x].rs].mn) return query(t[x].ls,p);
else return query(t[x].rs,p);return ;
} int main(){
scanf("%d%lf",&n,&k);rt=o++;
for(int i=;i<=n;i++) scanf("%d",&a[i]);
sort(a+,a++n,cmp);build(rt,,n);
for(int i=n-;i;i--)
if(a[i]==a[i+]) cnt[i]=cnt[i+]+;
else cnt[i]=;
for(int i=;i<=n;i++)
fa[i]=(int)floor(i/k),siz[i]=;
for(int i=n;i;i--) siz[fa[i]]+=siz[i];
for(int i=;i<=n;i++){
if(fa[i]&&fa[i]!=fa[i-])
update(rt,ans[fa[i]],n,siz[fa[i]]-);
int x=query(rt,siz[i]);ans[i]=x;
x+=cnt[x];cnt[x]++;x-=(cnt[x]-);
update(rt,x,n,-siz[i]);
} for(int i=;i<=n;i++)
printf("%d ",a[ans[i]]);
return ;
}

贪心+线段树

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

  1. [BZOJ5249][九省联考2018]IIIDX(线段树)

    5249: [2018多省省队联测]IIIDX Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 32  Solved: 17[Submit][Statu ...

  2. BZOJ5249 九省联考2018IIIDX(线段树+贪心)

    显然这形成了一个树形结构.考虑这样一种贪心:按照曲目顺序,每次取消其父亲的预留,并选择当前可选择(保证其子树有合法选择且满足预留)的最大值,然后对其子树预留出大于等于他的一些值.这个做法显然是正确的. ...

  3. 省选九省联考T2 IIIDX(线段树)

    题目传送门:https://www.luogu.org/problemnew/show/P4364 期中考后记:期中考刚考完,感觉不咋滴,年排第3.我抗压力太差了..期末得把rank1抢回来. 本来感 ...

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

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

  5. [BZOJ 5252][LOJ 2478][九省联考2018] 林克卡特树

    [BZOJ 5252][LOJ 2478][九省联考2018] 林克卡特树 题意 给定一个 \(n\) 个点边带权的无根树, 要求切断其中恰好 \(k\) 条边再连 \(k\) 条边权为 \(0\) ...

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

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

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

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

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

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

  9. [九省联考2018]IIIDX

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

随机推荐

  1. 毕业N年后,请不要像我一样被档案烦死

    目录 一. 提醒大学生:深刻重视档案,避免以后麻烦! 二.说说我因为档案造成的烦心事! 三.说说档案这档子事: 四.档案如此重要,为什么有些人却成了弃档族? 五.档案该怎么操作才能不当"弃档 ...

  2. 类的property特性

    目录 什么是 property特性 简单示例 property属性的两种方式 装饰器 类属性方式 property+类的封装 应用 私有属性添加getter和setter方法 使用property升级 ...

  3. 【MySQL】全量+增量的备份/恢复

    生产环境中,有时需要做MySQL的备份和恢复工作.因MySQL是在运行过程中的,做全量备份需要时间,全量备份完成后又有数据变动,此时需要增量备份辅助.如果想恢复数据到一个空库(例如数据迁移或者上云等更 ...

  4. Linux 软连接和硬连接(转)

    1.Linux链接概念Linux链接分两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link).默认情况下,ln命令产生硬链接. [硬连接]硬连接指通过索引节点 ...

  5. BZOJ2152聪聪可可

    bzoj传送门 luogu传送门 这题算是很sb的点分治了,最近在点分治复习,写了练练手,对于这个题只需要对统计0,1,2出现的次数就好了吧,然后发现答案不对,也就是每个点对需要算两遍嘛,0也算,所以 ...

  6. hibernate Day2 案例代码

    1.编写实体类Person package com.icss.pojo; public class Person { private int uid; private String uname; pr ...

  7. HTML超链接的使用

    基本语法 <a href="" target="打开方式" name="页面锚点名称">链接文字或图片</a> 属性 ...

  8. django-form and fields validation

    参考资料 清除数据与表单验证 清除数据时会进行表单验证. 在表格处理时有三种clean方法可调用,通常是在对表单调用is_valid()时执行. clean响应:一般有两种结果,如果处理的数据有问题, ...

  9. setTimeout的核心原理和巧用

    你所不了解的setTimeout 发表于 2015年11月23日 by 愚人码头 被浏览 14,756 次 分享到: 0 小编推荐:掘金是一个高质量的技术社区,从 ECMAScript 6 到 Vue ...

  10. Mysql->order by SQL 根据多个条件排序

    Mysql中根据多个条件排序:(各个条件间使用逗号隔开)   首先根据class_name字符串长短升序排列,然后根据开始时间降序排列: SELECT * FROM signup_class s OR ...