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;
}
原文地址:https://www.cnblogs.com/youth518/p/14461813.html