zoukankan      html  css  js  c++  java
  • loj2472[九省联考2018]IIIDX

    题意:要求构造一个d的排列使得满足d[i/k]<=d[u]且字典序最大。

    标程(bzoj上并不能过):

     1 #include<bits/stdc++.h>
     2 #define mid ((l+r)>>1)
     3 using namespace std;
     4 const int N=500005;
     5 const int eps=1e-7;
     6 double k;
     7 int tag[N<<2],sum[N<<2],size[N],n,fa[N],ans[N],d[N];
     8 map<int,int> to;
     9 bool cmp(int A,int B){return A>B;}
    10 void up(int k) {sum[k]=min(sum[k<<1],sum[k<<1|1]);}
    11 void down(int k)
    12 {
    13   if (tag[k])
    14   {
    15     tag[k<<1]+=tag[k];tag[k<<1|1]+=tag[k];
    16     sum[k<<1]+=tag[k];sum[k<<1|1]+=tag[k];
    17     tag[k]=0;
    18   }
    19 }
    20 void build(int k,int l,int r)
    21 {
    22   if (l==r) {sum[k]=l;return;}
    23   build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    24   up(k);
    25 }
    26 void add(int k,int l,int r,int L,int R,int x)
    27 {
    28   if (L<=l&&r<=R) {sum[k]+=x;tag[k]+=x;return;}
    29   down(k);
    30   if (L<=mid) add(k<<1,l,mid,L,R,x);
    31   if (R>mid) add(k<<1|1,mid+1,r,L,R,x); 
    32   up(k);
    33 } 
    34 int qry(int k,int l,int r,int x)
    35 {
    36   if (l==r) return (x<=sum[k])?l:l+1;
    37   down(k);int res;
    38   if (x<=sum[k<<1|1]) res=qry(k<<1,l,mid,x);
    39   else res=qry(k<<1|1,mid+1,r,x);
    40   up(k);//由于前面down标记,查询时也需要up来更新
    41   return res;
    42 }
    43 int main()
    44 { 
    45   scanf("%d%lf",&n,&k);
    46   for (int i=1;i<=n;i++) scanf("%d",&d[i]),fa[i]=(int)((double)i/k+eps);
    47   for (int i=n;i>=1;i--) size[i]++,size[fa[i]]+=size[i];
    48   build(1,1,n);
    49   sort(d+1,d+n+1,cmp);
    50   for (int i=n;i>=1;i--) if (d[i]!=d[i+1]) to[d[i]]=i; 
    51   for (int i=1;i<=n;i++)
    52   {
    53     if (fa[i]&&fa[i]!=fa[i-1]) add(1,1,n,ans[fa[i]],n,size[fa[i]]-1);
    54     int t=qry(1,1,n,size[i]); ans[i]=to[d[t]]--;
    55     add(1,1,n,ans[i],n,-size[i]);
    56   }
    57   for (int i=1;i<=n;i++) printf("%d ",d[ans[i]]);
    58   return 0;
    59 }
    View Code

    题解:线段树+占位

    如果直接贪心:从上到下贪心然后把最小的派给编号最大的是不对的。1 1 1 2 应该是1 1 2 1。

    直接按编号从小到大考虑。每一层用size占位,线段树维护从小到大的d序列,每一位表示当前位前面有多少个数没被使用。每次选择最靠前的一个sum[x]>=size[i](单调),如果找到x周围有若干个和sum[x]相等,那么选取最靠后的一个(贪心)。如果当前子树的父亲已经处理完毕,那么还原,继续处理儿子。

  • 相关阅读:
    如何探索汽车后市场B2B和B2C商业模式?
    当下汽车后市场现状是什么的样?
    怎样解释汽车后市场是什么?
    全球第一开源ERP Odoo操作手册 数据库简介 增加预读提升Odoo文件读取性能
    全球第一开源ERP Odoo操作手册 数据库自动备份
    全球第一开源ERP Odoo操作手册 启用多核来提升Odoo性能
    全球第一开源ERP Odoo操作手册 使用Nginx Upstream来优化Odoo的网络传输性能
    全球第一开源ERP Odoo操作手册 安装ssh服务和ssh客户端
    DES对称加密
    linux下安装python3.7
  • 原文地址:https://www.cnblogs.com/Scx117/p/9197326.html
Copyright © 2011-2022 走看看