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

    (d_i) 互不相同时,建出树后,按树的后序遍历,优先遍历编号小的点得到的顺序,(d_i) 从大到小填,即为最优解。

    (d_i) 不保证互不相同时,这个贪心就不对了。设 (f_i)([1,i]) 中有多少个 (d_i) 可以填,那么所有满足 (minlimits_{j=i}^n { f_j } geqslant size_x) 的位置 (i) 都可以填到节点 (x)

    那么肯定是填最靠右的位置最优,设当前填的位置为 (pos),那么就要在 ([pos+1,n]) 中的 (f_i) 都减去 (size_x)。当遍历到某个节点的第一棵子树时,需撤销该节点的限制。

    用线段树即可实现,修改就是区间加,询问就是在线段树上二分。

    #include<bits/stdc++.h>
    #define maxn 1000010
    #define maxm 4000010
    #define ls (cur<<1)
    #define rs (cur<<1|1)
    #define mid ((l+r)>>1)
    using namespace std;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,root=1;
    double k;
    int ans[maxn],fa[maxn],siz[maxn],d[maxn],pos[maxn],mn[maxm],add[maxm];
    void pushadd(int cur,int v)
    {
        mn[cur]+=v,add[cur]+=v;
    }
    void pushdown(int cur)
    {
        if(!add[cur]) return;
        pushadd(ls,add[cur]),pushadd(rs,add[cur]),add[cur]=0;
    }
    void build(int l,int r,int cur)
    {
        if(l==r)
        {
            mn[cur]=l;
            return;
        }
        build(l,mid,ls),build(mid+1,r,rs);
        mn[cur]=min(mn[ls],mn[rs]);
    }
    void modify(int L,int R,int l,int r,int v,int cur)
    {
        if(L<=l&&R>=r)
        {
            pushadd(cur,v);
            return;
        }
        pushdown(cur);
        if(L<=mid) modify(L,R,l,mid,v,ls);
        if(R>mid) modify(L,R,mid+1,r,v,rs);
        mn[cur]=min(mn[ls],mn[rs]);
    }
    int query(int l,int r,int v,int cur)
    {
        if(l==r) return mn[cur]>=v?l:l+1;
        pushdown(cur);
        if(mn[rs]>=v) return query(l,mid,v,ls);
        return query(mid+1,r,v,rs);
    }
    int main()
    {
        read(n),scanf("%lf",&k),build(1,n,root);
        for(int i=1;i<=n;++i) read(d[i]);
        sort(d+1,d+n+1),reverse(d+1,d+n+1);
        for(int i=n;i;--i) pos[i]=d[i]==d[i+1]?pos[i+1]:i;
        for(int i=1;i<=n;++i) fa[i]=i/k;
        for(int i=n;i;--i) siz[i]++,siz[fa[i]]+=siz[i];
        for(int i=1;i<=n;++i)
        {
            if(fa[i]&&fa[i]!=fa[i-1]) modify(ans[fa[i]],n,1,n,siz[fa[i]]-1,root);
            ans[i]=pos[query(1,n,siz[i],root)],modify(ans[i],n,1,n,-siz[i],root);
        }
        for(int i=1;i<=n;++i) printf("%d ",d[ans[i]]);
        return 0;
    }
    
  • 相关阅读:
    Flutter form 的表单 input
    FloatingActionButton 实现类似 闲鱼 App 底部导航凸起按钮
    Flutter 中的常见的按钮组件 以及自 定义按钮组件
    Drawer 侧边栏、以及侧边栏内 容布局
    AppBar 自定义顶部导航按钮 图标、颜色 以及 TabBar 定义顶部 Tab 切换 通过TabController 定义TabBar
    清空路由 路由替换 返回到根路由
    应对ubuntu linux图形界面卡住的方法
    [转] 一块赚零花钱
    [转]在树莓派上搭建LAMP服务
    ssh保持连接
  • 原文地址:https://www.cnblogs.com/lhm-/p/13908072.html
Copyright © 2011-2022 走看看