洛谷 4364 [九省联考2018]IIIDX——“预留”的思路
题目:https://www.luogu.org/problemnew/show/P4364
原来想了一个错误的思路,就是这样:
solve( cr , l , r ) 表示 cr 为根的子树填 [ l , r ] 的数;然后把 l 给 cr ,剩下的 [ l+1 , r ] 分成一段一段,大的段给标号小的孩子。
然后只能得 60 分。
#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; }
看了看题解。https://files-cdn.cnblogs.com/files/NaVi-Awson/IIIDX.pdf
关于 “去掉父亲预留的影响” ,是这样考虑:
按顺序枚举节点,在树上就是像 bfs 一样遍历;
一个点 cr 要预留,是为了让 “和它深度相同的点” 不要抢了它的位置。
当开始遍历 cr 的子树的时候,直接去掉 cr 的影响并再也不加入了;这样不会有错,因为此时不会再遍历和 cr 深度相同的点了;
下一层的点已经由它们的父亲留好了位置,所以去掉 cr 的影响也不会让之后的点出错。
还有一种不太能理解的做法:https://www.cnblogs.com/HocRiser/p/8742680.html
#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; }