In mathematics you don't understand things, you just get used to them.

Description

Link.

给出一个堆,然后让你填数进去,使得其满足小根堆的性质,并使编号靠前的点的数最大。

Solution

考虑贪心,把原数列降序排序,然后因为这个东西是整除分块的形式,所以一个结点的子树一定对应的是原序列的一个子区间。不过这个东西并不能用根号分治来做。

然后对于一个子树的根 $u$,我们给他 $[l,r]$ 这个区间,$\text{subtree}(u)-\{u\}=a_{[l,r)}$,结点 $u=a_{r}$,$[l,r]$ 按需分配,反正就优先队列维护就行了。

代码大概长成这样子:

void Search(int x) {
  for(int y in SonOf(x)) Search(y);
  if(x != VirtualRoot) {
    ans[x] = PriorityQueue.top();
    PriorityQueue.pop();
  }
}

那个 VirtualRoot 是为了编码方便弄出来的一个虚根,不用管。同时发现这个做法只有在 $\forall i,j,s.t.d_{i}\neq d_{j}$ 的时候才是对的。Hack 数据网上找找应该有。

对于一个与 $u$ 同层的结点,可能会出现这个结点与 $u$ 的儿子交换点权后更优的情况。

对值域 $[1,n]$ 建出一棵线段树,同时定义 $pos_{i}$ 为 $\max\{j\mid a_{i}=a_{i+1}=\cdots=a_{j}\}$。然后每次查找能用的个数不小于该结点子树大小的位置,有多解跑到最右边,然后把这个位置的能用个数减去子树大小。描述的不清楚,建议做代码阅读理解领略一下精神。

#include<bits/stdc++.h>
struct node
{
    int mn,tag;
    node(int A=0,int B=0)
    {
        mn=A;
        tag=B;
    }
}nodes[2000010];
std::vector<std::vector<int> > e;
int n,siz[500010],ans[500010];
double k;
void dfs(int x)
{
    siz[x]=1;
    for(int i=0;i<int(e[x].size());++i)
    {
        int y=e[x][i];
        dfs(y);
        siz[x]+=siz[y];
    }
}
void build(int l,int r,int x)
{
    if(l^r)
    {
        int mid=(l+r)>>1;
        build(l,mid,x<<1);
        build(mid+1,r,x<<1|1);
        nodes[x].mn=std::min(nodes[x<<1].mn,nodes[x<<1|1].mn);
    }
    else    nodes[x].mn=l;
}
void push_down(int x)
{
    if(nodes[x].tag)
    {
        int &cur=nodes[x].tag;
        nodes[x<<1].mn+=cur;
        nodes[x<<1|1].mn+=cur;
        nodes[x<<1].tag+=cur;
        nodes[x<<1|1].tag+=cur;
        cur=0;
    }
}
void ins(int l,int r,int x,int fr,int ba,int delta)
{
    if(l>ba || r<fr)    return;
    if(l>=fr && r<=ba)
    {
        nodes[x].mn+=delta;
        nodes[x].tag+=delta;
    }
    else
    {
        int mid=(l+r)>>1;
        push_down(x);
        ins(l,mid,x<<1,fr,ba,delta);
        ins(mid+1,r,x<<1|1,fr,ba,delta);
        nodes[x].mn=std::min(nodes[x<<1].mn,nodes[x<<1|1].mn);
    }
}
int find(int l,int r,int x,int d)
{
    if(l^r)
    {
        int mid=(l+r)>>1;
        push_down(x);
        if(d<=nodes[x<<1|1].mn)    return find(l,mid,x<<1,d);
        else    return find(mid+1,r,x<<1|1,d);
    }
    else    return l+(nodes[x].mn<d);
}
int getDiv(int x,double k)
{
    return int(std::floor(double(x)/k));
}
int main()
{
    scanf("%d %lf",&n,&k);
    e.resize(n+1);
    std::vector<int> a(n+10),pos(n+10);
    for(int i=1;i<=n;++i)    scanf("%d",&a[i]);
    std::sort(a.begin()+1,a.begin()+n+1,std::greater<int>());
    for(int i=n-1;i;--i)
    {
        if(a[i]==a[i+1])    pos[i]=pos[i+1]+1;
    }
    for(int i=1;i<=n;++i)    e[getDiv(i,k)].emplace_back(i);
    dfs(0);
    build(1,n,1);
    for(int i=1;i<=n;++i)
    {
        if(getDiv(i,k)^getDiv(i-1,k))    ins(1,n,1,ans[getDiv(i,k)],n,siz[getDiv(i,k)]-1);
        int tmp=find(1,n,1,siz[i]);
        tmp+=pos[tmp];
        ++pos[tmp];
        tmp-=pos[tmp]-1;
        ans[i]=tmp;
        ins(1,n,1,tmp,n,-siz[i]);
    }
    for(int i=1;i<=n;++i)    printf("%d ",a[ans[i]]);
    return 0;
}

data structures trees

Solution -「CF 1025D」Recovering BST
上一篇 «
Solution -「CF 724F」Uniformly Branched Trees
» 下一篇