ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P4364 [九省联考2018]IIIDX 题解

2021-10-23 09:02:17  阅读:137  来源: 互联网

标签:sz dl return int 题解 void P4364 read 联考


Luogu
Solution Link

Description.

给定一棵树,第 \(i\) 个点的父亲是 \(\lfloor\frac ik\rfloor\)。
有一些权值,你需要对每个节点附上一个权值,满足每个点都比他所有后代小,使得权值构成的序列字典序最大。

Solution.

逐位确定。
第 \(i\) 位填完后,相当于多了一个限制,就是至少有 \(sz_i-1\) 个数 \(\ge b_i\)。
注意这个限制在一个节点所有孩子被确定后会消失,因为都变成了孩子自己的限制了。

考虑维护这件事情:

  • 插入一个形如要至少有 \(k\) 个数 \(\ge b\) 的限制
  • 删除一个限制
  • 找到一个最大的可以被取的数
  • 删掉一个数

考虑 \(f_i\) 表示只考虑 \(b\ge i\) 的限制有多少个可以取。
则初始就是出现个数的后缀和。
我们每次要找到一个最后面的满足 \(f_i\ge sz\),这个可以线段树二分,维护前缀 \(\min\)。
多一个限制相当于前缀减 \(k\),少一个数相当于前缀减 \(1\)。
然后就做完了。

Coding.

点击查看代码
//是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<'0'||c>'9';c=getchar()) if(c=='-') f=1;
	for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	if(f) x=-x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int N=500005;double k;
int n,ut,w[N],fa[N],tn[N],rs[N],sz[N],tg[N],cn[N];
namespace segment
{
	struct seg{int mn,tg;}T[N<<2];
	inline void pushup(int x) {T[x].mn=min(T[x<<1].mn,T[x<<1|1].mn);}
	inline void allc(int x,int w) {T[x].mn+=w,T[x].tg+=w;}
	inline void pushdw(int x) {if(T[x].tg) allc(x<<1,T[x].tg),allc(x<<1|1,T[x].tg),T[x].tg=0;}
	inline void build(int x,int l,int r)
	{
		if(l==r) return T[x].mn=cn[l],void();
		build(x<<1,l,(l+r)>>1),build(x<<1|1,((l+r)>>1)+1,r),pushup(x);
	}
	inline void modif(int x,int l,int r,int dl,int dr,int dc)
	{
		if(l>dr||dl>r) return;else if(dl<=l&&r<=dr) return allc(x,dc);else pushdw(x);
		modif(x<<1,l,(l+r)>>1,dl,dr,dc),modif(x<<1|1,((l+r)>>1)+1,r,dl,dr,dc),pushup(x);
	}
	inline int query(int x,int l,int r,int k)
	{
		if(l==r) return l;else pushdw(x);
		if(T[x<<1].mn<k) return query(x<<1,l,(l+r)>>1,k);
		else return query(x<<1|1,((l+r)>>1)+1,r,k);
	}
	inline int qry(int w) {return T[1].mn>=w?ut:query(1,1,ut,w)-1;}
	inline void debug(int x,int l,int r)
	{
		if(l==r) return printf("%d ",T[x].mn),void();else pushdw(x);
		debug(x<<1,l,(l+r)>>1),debug(x<<1|1,((l+r)>>1)+1,r);
	}
}using namespace segment;
int main()
{
	read(n),scanf("%lf",&k);for(int i=1;i<=n;i++) read(w[i]),sz[i]=1;
	for(int i=1;i<=n;i++) fa[i]=int(i/k),tn[++ut]=w[i];
	sort(tn+1,tn+ut+1),ut=unique(tn+1,tn+ut+1)-tn-1;
	for(int i=1;i<=n;i++) ++cn[w[i]=lower_bound(tn+1,tn+ut+1,w[i])-tn];
	for(int i=ut;i>=1;i--) cn[i]+=cn[i+1];
	sz[0]=1;for(int i=n;i>=1;i--) sz[fa[i]]+=sz[i];
	//for(int i=0;i<=n;i++) printf("%d%c",sz[i],i==n?'\n':' ');
	tg[0]=1,build(1,1,ut);
	for(int i=1,v;i<=n;i++)
	{
		if(!tg[fa[i]]) modif(1,1,ut,1,rs[fa[i]],sz[fa[i]]-1),tg[fa[i]]=1;
		//debug(1,1,ut),putchar('\n');
		rs[i]=v=qry(sz[i]),modif(1,1,ut,1,v,-sz[i]);
		//printf("! %d ( %d %d\n",v,i,sz[i]);
	}
	for(int i=1;i<=n;i++) printf("%d%c",tn[rs[i]],i==n?'\n':' ');
	return 0;
}

标签:sz,dl,return,int,题解,void,P4364,read,联考
来源: https://www.cnblogs.com/pealfrog/p/15441263.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有