题目:​​https://www.luogu.org/problemnew/show/P4364​

原来想了一个错误的思路,就是这样:

  solve( cr , l , r ) 表示 cr 为根的子树填 [ l , r ] 的数;然后把 l 给 cr ,剩下的 [ l+1 , r ] 分成一段一段,大的段给标号小的孩子。

然后只能得 60 分。


洛谷 4364 [九省联考2018]IIIDX——“预留”的思路_子树洛谷 4364 [九省联考2018]IIIDX——“预留”的思路_#define_02


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#define db double
#define pb push_back
using namespace std;
int rdn()
{
int ret=0;bool fx=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
return fx?ret:-ret;
}
const int N=5e5+5;
int n,d[N],p[N],siz[N]; db k;
vector<int> vt[N];
void dfs(int cr)
{
siz[cr]=1;
for(int i=0,lm=vt[cr].size();i<lm;i++)
dfs(vt[cr][i]), siz[cr]+=siz[vt[cr][i]];
}
void solve(int cr,int l,int r)
{
p[cr]=d[l]; int p0=l;
for(int i=vt[cr].size()-1;i>=0;i--)
{
solve(vt[cr][i],p0+1,p0+siz[vt[cr][i]]);
p0+=siz[vt[cr][i]];
}
}
int main()
{
n=rdn();scanf("%lf",&k);
for(int i=1;i<=n;i++)d[i]=rdn();
sort(d+1,d+n+1);
for(int i=1;i<=n;i++)
vt[(int)floor(i/k)].pb(i);
dfs(0); solve(0,0,n);
for(int i=1;i<=n;i++)printf("%d ",p[i]);
puts(""); return 0;
}

View Code

关于 “去掉父亲预留的影响” ,是这样考虑:

  按顺序枚举节点,在树上就是像 bfs 一样遍历;

  一个点 cr 要预留,是为了让 “和它深度相同的点” 不要抢了它的位置。

  当开始遍历 cr 的子树的时候,直接去掉 cr 的影响并再也不加入了;这样不会有错,因为此时不会再遍历和 cr 深度相同的点了;

  下一层的点已经由它们的父亲留好了位置,所以去掉 cr 的影响也不会让之后的点出错。



#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
int rdn()
{
int ret=0;bool fx=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
return fx?ret:-ret;
}
int Mn(int a,int b){return a<b?a:b;}
int Mx(int a,int b){return a>b?a:b;}
const int N=5e5+5,M=N<<1;
int n,a[N],fa[N],ans[N],siz[N],tp[N],tx[N];
int tot,Ls[M],Rs[M],mn[M],tg[M];
void pshp(int cr){mn[cr]=Mn(mn[ls],mn[rs]);}
void build(int l,int r,int cr)
{
if(l==r){mn[cr]=n-l;return;}
int mid=l+r>>1;
ls=++tot; build(l,mid,ls);
rs=++tot; build(mid+1,r,rs);
pshp(cr);
}
void pshd(int cr)
{
if(!tg[cr])return; int w=tg[cr]; tg[cr]=0;
tg[ls]+=w; tg[rs]+=w; mn[ls]+=w; mn[rs]+=w;
}
void mdfy(int l,int r,int cr,int L,int R,int k)
{
if(l>=L&&r<=R){tg[cr]+=k;mn[cr]+=k;return;}
int mid=l+r>>1; pshd(cr);
if(L<=mid)mdfy(l,mid,ls,L,R,k);
if(mid<R)mdfy(mid+1,r,rs,L,R,k);
pshp(cr);
}
int qry(int l,int r,int cr,int k)
{
if(l==r)return mn[cr]>=k?l:-1;
int mid=l+r>>1,ret=-1; pshd(cr);
if(mn[ls]>=k)ret=qry(mid+1,r,rs,k);
if(ret>=0)return ret;
return qry(l,mid,ls,k);
}
int main()
{
n=rdn(); double sl; scanf("%lf",&sl);
for(int i=1;i<=n;i++)a[i]=rdn();
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)tp[i]=a[i];
int m=unique(tp+1,tp+n+1)-tp-1;
for(int i=1;i<=n;i++)
{
a[i]=lower_bound(tp+1,tp+m+1,a[i])-tp;
tx[a[i]]++;
}
for(int i=2;i<=m;i++)tx[i]+=tx[i-1];
for(int i=1;i<=n;i++) fa[i]=floor(i/sl);
for(int i=n;i;i--) siz[i]++,siz[fa[i]]+=siz[i];
tot=1; build(0,n,1);
for(int i=1;i<=n;i++)
{
if(i>1&&fa[i]!=fa[i-1])
mdfy(0,n,1,0,ans[fa[i]]-1,siz[fa[i]]-1);
//-1 for already use
int p=qry(0,n,1,siz[i])+1;
p=++tx[a[p]-1];//
ans[i]=p;
mdfy(0,n,1,0,p-1,-siz[i]);
}
for(int i=1;i<=n;i++)printf("%d ",tp[a[ans[i]]]);
puts(""); return 0;
}