• Solution -「九省联考 2018」IIIDX


    Description

    Link.

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

    Solution

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

    然后对于一个子树的根 (u),我们给他 ([l,r]) 这个区间,( ext{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} eq d_{j}) 的时候才是对的。Hack 数据网上找找应该有。

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

    对值域 ([1,n]) 建出一棵线段树,同时定义 (pos_{i})(max{jmid 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;
    }
    
  • 相关阅读:
    2019-2020-2 网络对抗技术 20175318 Exp0 kali Linux系统的安装(雾
    手动编译 TCP BBR v2 Alpha/Preview 内核
    Adobe Flash Player解除限制版
    ABBYY FineReader 15.0.18.1494 Corporate Multilingual破解
    易语言5.9精简学习增强版
    Debian9 快速开启 TCP BBR 实现高效单边加速
    ucosii-2(选做)
    Ubuntu 18.04/18.10快速开启Google BBR的方法
    基于 Nginx 的 v2+websocket+tls 域名伪装
    Google TCP升级版加速:BBR 2.0对比BBR Plus
  • 原文地址:https://www.cnblogs.com/orchid-any/p/14631402.html
Copyright © 2020-2023  润新知