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

    我被自己菜惊了。

    一道小题思路错两次

    怕是没救了。

    硬是写了2个晚上……

    对于每个位置,选能选的最大数。但是要记得预留子树里的数字。

    感性地说:如果没有重复数,自然是“挤满”的,但是有重复数后就可能有空余。

    离散化,对于每个数字用线段树记录比它大的数中,数的个数减去已确定的不能选的数的个数。

    如果两点的数冲突,即两数预留的数中有冲突,那么从这两个数到最大数显然都选了并有数被选两次,即预留的数个数大于区间内总的数个数。

    则比两数小的数中必然有数的线段树中的值小于0。

    故只要均大于0就合法。以此二分找当前能选的最大数即可。

    另外注意:每次新到一个父节点要把其预留的数“释放”给子节点。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    const int maxn = 2500005;
    const int inf = 0x3f3f3f3f;
    int n, d[maxn], tm, y[maxn], bigger[maxn];
    int ans[maxn], c[maxn], kk[maxn], lsum[maxn];
    double k;
    
    struct atree {
        #define ls (x*2)
        #define rs (x*2+1)
        int minn[maxn], tag[maxn];
        void down(int x) {
            minn[ks]+=tag[x]; tag[ls]+=tag[x];
            minn[rs]+=tag[x]; tag[rs]+=tag[x];
            tag[x]=0;
        }
        void add(int x, int l, int r, int a, int b, int k) {
            if(l > b || a > r) return;
            if(a <= l && r <= b) { minn[x]+=k; tag[x]+=k; return; }
            int mid=(l+r)/2;
            down(x);
            add(ls, l, mid, a, b, k);
            add(rs, mid+1, r, a, b, k);
            minn[x]=min(minn[x*2], minn[x*2+1]);
            return;
        }
        int count(int x, int l, int r, int a, int b) {
            if(l > b || a > r) return inf;
            if(a <= l && r <= b) { return minn[x]; }
            int mid=(l+r)/2, t;
            down(x);
            t=min(count(ls, l, mid, a, b), count(rs, mid+1, r, a, b));
            minn[x]=min(minn[x*2], minn[x*2+1]);
            return t;
        }
    } T;
    
    inline int find_p(int x) {
        int l=1, r=tm, mid;
        while(l < r) {
            mid=(l+r+1)/2;
            if(T.count(1, 1, n+1, 1, mid) < x) r=mid-1;
            else l=mid;
        }
        return l;
    }
    
    int main() {
        int i, t, tt, sum=0, tc=0;
        cin>>n>>k;
        for(i=1; i <= n; i++) cin>>d[i];
        sort(d+1, d+1+n);
        for(i=1; i <= n; i++) {
            if(i == 1 || d[i] != d[i-1]) tm++, y[tm]=d[i];
            T.add(1, 1, n+1, 1, tm, 1);
            bigger[i]=1;
        }
        for(i=n; i >= 1; i--) {
            t=(double)i*1.0/k;
            bigger[t]+=bigger[i];
        }
        for(i=1; i <= n; i++) {
            t=(double)i*1.0/k;
            tt=(double)(i-1.0)*1.0/k;
            if(tt != t && t != 0) T.add(1, 1, n+1, 1, ans[t]-1+1, bigger[t]-1);
            t=find_p(bigger[i]);
            ans[i]=t;
            T.add(1, 1, n+1, 1, t-1+1, -bigger[i]);
            cout<<y[t]<<' ';
        }
        return 0;
    }
  • 相关阅读:
    Linux内核之系统调用
    [转]Linux最多支持的SCSI Disk的数目
    bash一些技巧
    [转]Iptables 规则 一些简单实例和详细介绍
    近来工作和面试一些人的感受(原)
    自动给URL地址加上超链接
    在ASP.NET虚拟主机上实现URL重写(UrlRewrite)
    使用Office组件读取Excel,引用Microsoft.Office.Interop.Excel出现的问题
    Fixing Twitter 提高世界上最流行的微博客系统性能和可扩展性(转)
    从优酷网学习SEO的标题(title)和关键字(keywords)如何选择
  • 原文地址:https://www.cnblogs.com/crraphael/p/11479694.html
Copyright © 2011-2022 走看看