1. 程式人生 > >[貪心 線段樹] LOJ#2472. 「九省聯考 2018」IIIDX

[貪心 線段樹] LOJ#2472. 「九省聯考 2018」IIIDX

從1到n列舉,逐位確定。

首先可以把關係樹建出來,一個點的權值要大於等於父節點的權值。

如果沒有相同數字的,第 i 以及它子樹種的點會選擇 [nsizei+1,n] 這個區間裡的數,選完後把這個區間刪去,繼續考慮 i+1

如果有重複的數字,那麼第 i 個點會選擇第 nsizei+1 大的數字,但是它的子樹中的點選擇的區間就不能確定。

ai 表示大於等於 i 的可以選擇的數的個數,bi 表示已經選了多少個大於等於 i 的數

那麼如果當前考慮 i 點,i 點選擇的數為 pp 肯定會盡可能的大),那麼我們就會選擇

sizei 個大於等於 p 的數。

可以發現,如果 i 能選擇 p,那麼對於任何一個小於等於 pj 都滿足 bj+sizeiaj

也就是 sizeiajbj ,用線段樹記錄 ajbj ,然後線上段樹上二分一下 p 就可以了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <vector>
#define ALL(x) (x).begin(),(x).end()
using namespace std; typedef pair<int,int> pii; const int N=500010; int n,cnt,b[N],a[N],G[N],size[N],ans[N],son[N],dpt[N],fa[N]; double k; struct edge{ int t,nx; }E[N]; vector<int> sb; inline void addedge(int x,int y){ E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt; } void dfs(int x){ size[x]=1
; for(int i=G[x];i;i=E[i].nx){ dpt[E[i].t]=dpt[x]+1; dfs(E[i].t); size[x]+=size[E[i].t]; fa[E[i].t]=x; } } int mn[N<<2],tag[N<<2]; inline void Up(int g){ mn[g]=min(mn[g<<1]+tag[g<<1],mn[g<<1|1]+tag[g<<1|1]); } void build(int g,int l,int r){ if(l==r) return mn[g]=b[l],void(); int mid=l+r>>1; build(g<<1,l,mid); build(g<<1|1,mid+1,r); Up(g); } vector<int> Q[N]; void Modify(int g,int l,int r,int L,int R,int x){ if(l==L && r==R) return tag[g]+=x,void(); int mid=L+R>>1; if(r<=mid) Modify(g<<1,l,r,L,mid,x); else if(l>mid) Modify(g<<1|1,l,r,mid+1,R,x); else Modify(g<<1,l,mid,L,mid,x),Modify(g<<1|1,mid+1,r,mid+1,R,x); Up(g); } int Query(int s){ int g=1,l=1,r=n,ret; while(l<r){ int mid=l+r>>1; s-=tag[g]; if(mn[g<<1]+tag[g<<1]<s) r=mid,g=g<<1; else l=mid+1,g=g<<1|1,ret=mid; } if(mn[g]+tag[g]>=s) return l; return ret; } int main(){ scanf("%d%lf",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]),sb.push_back(a[i]); sb.push_back(0); sort(ALL(sb)); sb.erase(unique(ALL(sb)),sb.end()); for(int i=1;i<=n;i++) a[i]=lower_bound(ALL(sb),a[i])-sb.begin(); for(int i=1;i<=n;i++) addedge(i/k,i); dfs(0); for(int i=1;i<=n;i++) b[a[i]]++; for(int i=n;i;i--) b[i]+=b[i+1]; build(1,1,n); for(int i=1;i<=n;i++) Q[dpt[i]].push_back(i); for(int d=1;d<=dpt[n];d++){ for(int i=0;i<Q[d].size();i++){ if(d>1 && (i==0 || fa[Q[d][i]]!=fa[Q[d][i-1]])) Modify(1,1,ans[fa[Q[d][i]]],1,n,size[fa[Q[d][i]]]-1); int u=Q[d][i],p=Query(size[u]); ans[u]=p; Modify(1,1,p,1,n,-size[u]); } } for(int i=1;i<=n;i++) printf("%d ",sb[ans[i]]); return 0; }