[BZOJ5249][九省联考2018]IIIDX:线段树+贪心
分析
GXZlegend orz
构造出一组合法的解并不是难事,但是我们需要输出的是字典序最大的解。
字典序最大有另一种理解方式,就是让越小的数尽量越靠后。
我们从树的根结点出发,从1开始填数,构造出来的一定是一组合法的解。
对于每种相同的数,可以通过线段树上二分逐个确定他们的最优位置,具体细节可以看代码。
代码
#include <bits/stdc++.h>
#define rin(i,a,b) for(register int i=(a);i<=(b);++i)
#define irin(i,a,b) for(register int i=(a);i>=(b);--i)
#define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=500005;
int n,d[MAXN];
int ecnt,head[MAXN],siz[MAXN],ans[MAXN];
double k;
int sum[MAXN<<2],loc,ql,qr,kk;
struct Edge{
int to,nxt;
}e[MAXN<<1];
inline void add_edge(int bg,int ed){
++ecnt;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
head[bg]=ecnt;
}
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
void upd(int o,int l,int r){
if(l==r){
sum[o]+=kk;
return;
}
if(loc<=mid) upd(lc,l,mid);
else upd(rc,mid+1,r);
sum[o]=sum[lc]+sum[rc];
}
int query(int o,int l,int r){
if(l==r) return l;
if(sum[rc]>=kk) return query(rc,mid+1,r);
else return kk-=sum[rc],query(lc,l,mid);
}
#undef mid
#undef lc
#undef rc
int main(){
n=read();
scanf("%lf",&k);
rin(i,1,n) d[i]=read(),siz[i]=1;
std::sort(d+1,d+n+1);
rin(i,1,n) add_edge((int)floor(i/k),i);
irin(i,n,1) siz[(int)floor(i/k)]+=siz[i];
trav(i,0){int ver=e[i].to;loc=ver,kk=siz[ver];upd(1,1,n);}
int cnt=1;
rin(i,2,n+1){
if(d[i]==d[i-1]){#include <bits/stdc++.h>
#define rin(i,a,b) for(register int i=(a);i<=(b);++i)
#define irin(i,a,b) for(register int i=(a);i>=(b);--i)
#define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=500005;
int n,d[MAXN];
int ecnt,head[MAXN],siz[MAXN],ans[MAXN];
double k;
int sum[MAXN<<2],loc,ql,qr,kk;
struct Edge{
int to,nxt;
}e[MAXN<<1];
inline void add_edge(int bg,int ed){
++ecnt;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
head[bg]=ecnt;
}
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
void upd(int o,int l,int r){
if(l==r){
sum[o]+=kk;
return;
}
if(loc<=mid) upd(lc,l,mid);
else upd(rc,mid+1,r);
sum[o]=sum[lc]+sum[rc];
}
int query(int o,int l,int r){
if(l==r) return l;
if(sum[rc]>=kk) return query(rc,mid+1,r);
else return kk-=sum[rc],query(lc,l,mid);
}
#undef mid
#undef lc
#undef rc
int main(){
n=read();
scanf("%lf",&k);
rin(i,1,n) d[i]=read(),siz[i]=1;
std::sort(d+1,d+n+1);
rin(i,1,n) add_edge((int)floor(i/k),i);
irin(i,n,1) siz[(int)floor(i/k)]+=siz[i];
trav(i,0){int ver=e[i].to;loc=ver,kk=siz[ver];upd(1,1,n);}
int cnt=1;
rin(i,2,n+1){
if(d[i]==d[i-1]){
++cnt;
continue;
}
irin(j,cnt,1){
kk=j;int ret=query(1,1,n);ans[ret]=d[i-1];
loc=ret,kk=-siz[ret];upd(1,1,n);
trav(l,ret){
int ver=e[l].to;
loc=ver,kk=siz[ver];upd(1,1,n);
}
}
cnt=1;
}
rin(i,1,n) printf("%d ",ans[i]);
printf("\n");
return 0;
}
++cnt;
continue;
}
irin(j,cnt,1){
kk=j;int ret=query(1,1,n);ans[ret]=d[i-1];
loc=ret,kk=-siz[ret];upd(1,1,n);
trav(l,ret){
int ver=e[l].to;
loc=ver,kk=siz[ver];upd(1,1,n);
}
}
cnt=1;
}
rin(i,1,n) printf("%d ",ans[i]);
printf("\n");
return 0;
}
posted on 2019-02-27 22:33 ErkkiErkko 阅读(176) 评论(0) 编辑 收藏 举报