• P4364 [九省联考2018]IIIDX 线段树上二分


    题意:

    戳这里

    分析:

    • 暴力:

    对于 (d_i) 互不相同的情况,排序后从小到大给每个点分配子树大小的后缀,期望得分:50pts

    • 正解:

    可能存在一种情况就是,有一个子树内的较大值可以和另一个作为根的点互换,不改变大小关系的同时使得值更大,所以我们考虑不直接给每个点分值了,而是考虑有多少个大于 x 的值已经被选了,这样相当于发生了互换

    具体来说就是,我们对于每一个值个数为 (cnt_i) 表示大于等于 i 的能选的数有多少个,每当我们选择了某个根为 (x) ,也就是说对于小于等于 (x) 的值,能选的数全部减少了 (siz_i) ,而由于 (cnt) 是单调不增的,也就是说能选的数只会越来越少,所以我们每次对于一个点 (rt) 我们要找到一个最大的 (x) 满足 (min {cnt_1,cnt_2dots cnt_x}ge siz_{rt}) ,然后给 (cnt_1dots cnt_x) 区间减 (siz_{rt})

    区间修改需要线段树,然后每次在线段树上二分找最大的 (x) 就行了

    分析:

    #include<bits/stdc++.h>
    #define inl inline
    #define reg register
    #define lc rt<<1
    #define rc rt<<1|1
    
    using namespace std;
    
    namespace zzc
    {
        typedef long long ll;
        inl ll read()
        {
            ll x=0,f=1;char ch=getchar();
            while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
            while(isdigit(ch)) {x=x*10+ch-48;ch=getchar();}
            return x*f;
        }
    
        const ll maxn = 5e5+5;
        ll n,cnt;
        double k;
        ll fa[maxn],ans[maxn],siz[maxn],t[maxn],val[maxn<<2],a[maxn],b[maxn],tag[maxn<<2];
        bool vis[maxn];
        
        void pushdown(int rt)
        {
            if(tag[rt])
            {
                val[lc]+=tag[rt];tag[lc]+=tag[rt];
                val[rc]+=tag[rt];tag[rc]+=tag[rt];
                tag[rt]=0;
            }
        }
    
        void pushup(int rt)
        {
            val[rt]=min(val[lc],val[rc]);
        }
    
        void build(int rt,int l,int r)
        {
            if(l==r) 
            {
                val[rt]=t[l];
                return ;
            }
            int mid=(l+r)>>1;
            build(lc,l,mid);build(rc,mid+1,r);
            pushup(rt);
        }
    
        void modify(int rt,int l,int r,int ql,int qr,int w)
        {
            if(ql<=l&&r<=qr)
            {
                val[rt]+=w;
                tag[rt]+=w;
                return ;
            }
            pushdown(rt);
            int mid=(l+r)>>1;
            if(ql<=mid) modify(lc,l,mid,ql,qr,w);
            if(qr>mid) modify(rc,mid+1,r,ql,qr,w);
            pushup(rt);
        }
    
        int query(int rt,int l,int r,int w)
        {
            if(l==r) return val[rt]>=w?l:l-1;
            pushdown(rt);
            int mid=(l+r)>>1,res=0;
            if(val[lc]>=w) res=query(rc,mid+1,r,w);
            else res=query(lc,l,mid,w);
            pushup(rt);
            return res;
        }
    
        void work()
        {
            n=read();scanf("%lf",&k);
            for(reg ll i=1;i<=n;i++) a[i]=read(),b[i]=a[i],siz[i]=1;
            sort(b+1,b+n+1);cnt=unique(b+1,b+n+1)-b-1;
            for(reg ll i=1;i<=n;i++) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b,t[a[i]]++;
            for(reg ll i=cnt-1;i;i--) t[i]+=t[i+1];
            for(reg ll i=n;i;i--) fa[i]=floor(i/k),siz[fa[i]]+=siz[i];
            build(1,1,cnt);
            for(reg ll i=1;i<=n;i++)
            {
                int ff=floor(i/k);
                if(ff&&!vis[ff]) modify(1,1,cnt,1,ans[ff],siz[ff]-1);
                vis[ff]=true;
                int pos=query(1,1,cnt,siz[i]);
                modify(1,1,cnt,1,pos,-siz[i]);
                ans[i]=pos;
                printf("%lld ",b[pos]);
            }
        }
    
    }
    
    int main()
    {
        zzc::work();
        return 0;
    }
    
  • 相关阅读:
    一个例子学懂搜索引擎(lucene)
    在vs2008中设置jquery智能提示
    40个有用的jQuery技术和教程
    构建高性能ASP.NET站点之三 细节决定成败
    了解搜索引擎技术
    使用微软分布式缓存服务Velocity Part 2
    【转】构建高性能ASP.NET站点 开篇
    构建高性能ASP.NET站点之二 优化HTTP请求(前端)
    笔记:深入理解JVM 第4章 JVM性能监控与故障处理工具
    javascript 继承
  • 原文地址:https://www.cnblogs.com/youth518/p/14461813.html
Copyright © 2020-2023  润新知