题目:

  给出 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. 最长XX序列问题小结 By cellur925

    今天我们搞一搞几个经典序列问题之间的爱♂恨♂情♂仇. 首先我们看一看LIS(最长上升子序列)(From my onenote)

  2. ebullient(2018.10.25)

    结论巨好想,每一次操作可以看作把一个b往前移一位,另一个b往后移一位,逆序对个数不改变,判断即可做第一问. 此处代码仅给出第一问做法: #include<cstdio> #include& ...

  3. vi/vim打开文件提示Found a swap file by the name

    问题分析 有一次在远程连接主机时,用vi打开文件my.ini却提示:Found a swap file by the name ".my.ini.swp".百度了下才知道,原来在使 ...

  4. java数据结构----带权图

    1.带权图:要引入带权图,首先要引入最小生成树,当所有的边拥有相同的权值时.问题变得简单了,算法可以选择任意一条边加入最小生成树.但是当边有不同的权值时,需要用一些算法决策来选择正确的边. 2.带权图 ...

  5. java中数据的存放位置

    引用自java编程思想四----2.2.1 程序运行时,我们最好对数据保存到什么地方做到心中有数.特别要注意的是内存的分配.有六个地方都可以保存数据:(1) 寄存器.这是最快的保存区域,因为它位于和其 ...

  6. python 对mongdb的简单操作

    准备工作:1.选择安装合适的mongodb到本地电脑,2.创建mongodb实例,3,开启mongodb实例,4,下载pymongo第三方库,5.下载pycharm对mongodb可视化支持的插件mo ...

  7. 如何使用程序调用webApi接口

    如何使用程序调用webApi接口 在C#中,传统调用HTTP接口一般有两种办法: WebRequest/WebResponse组合的方法调用 WebClient类进行调用. 第一种方法抽象程度较低,使 ...

  8. Dubbo端口占用错误信息

    SEVERE: Exception sending context initialized event to listener instance of class com.common.SysCont ...

  9. Parenthesis UVALive - 4882 删除不必要的括号序列,模拟题 + 数据

    https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_probl ...

  10. (转载)Unity 优化总结

    Unity 优化总结 2017-03-10 | 发布 大海明月  zengfeng75@qq.com  | 分类 Unity  | 标签 Unity  优化 相关文档 UGUI 降低填充率技巧两则 U ...