[LOJ]#2472. 「九省联考 2018」IIIDX 线段树+贪心

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_36797646/article/details/88322891

Solution

按照大小关系连边之后得到一棵树,然后肯定是每次填入尽量大的数,如果当前连到第 x x 个点,那么就需要知道当前能用的数中最大的一个有 s i z e x size_x 个数大于等于它的数,考虑如何维护这个东西。如果直接维护现在每种数剩下多少个,就很难搞,反正我是没有搞出来,考虑换一个东西,维护大于等于每种数的还有多少个数能用,这样的话每次是一个区间加减,还有一个线段树上二分的操作。注意不能只减去现在已经填好了的数,还要减去以后将要被填入的数。然后每次填 x x 的时候,还要把父亲的加上。

Code

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=500010;
const int inf=2147483647;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
int A[Maxn],lA;
void write(int x)
{
	if(!x){putchar('0');putchar(' ');return;}
	lA=0;while(x)A[++lA]=x%10,x/=10;
	for(int i=lA;i;i--)putchar(48+A[i]);putchar(' ');
}
int n,cnt=0,sz[Maxn],s[Maxn],to[Maxn],b[Maxn],V[Maxn],fa[Maxn];double k;
bool mark[Maxn];
vector<int>d[Maxn],h[Maxn];
void dfs(int x)
{
	sz[x]=1;
	for(int i=0;i<h[x].size();i++)
	{
		int y=h[x][i];
		fa[y]=x;
		dfs(y);
		sz[x]+=sz[y];
	}
}
struct Seg{int l,r,lc,rc,c,tag;}tr[Maxn<<1];
int tot=0;
void Add(int x,int v){tr[x].tag+=v;tr[x].c+=v;}
void up(int x)
{
	int lc=tr[x].lc,rc=tr[x].rc;
	tr[x].c=min(tr[lc].c,tr[rc].c);
}
void down(int x)
{
	int lc=tr[x].lc,rc=tr[x].rc,t=tr[x].tag;
	if(t)tr[x].tag=0,Add(lc,t),Add(rc,t);
}
void build(int l,int r)
{
	int x=++tot;
	tr[x].l=l;tr[x].r=r;tr[x].tag=0;
	if(l==r){tr[x].c=s[l];return;}
	int mid=l+r>>1;
	tr[x].lc=tot+1,build(l,mid);
	tr[x].rc=tot+1,build(mid+1,r);
	up(x);
}
void add(int x,int l,int r,int v)
{
	if(tr[x].l==l&&tr[x].r==r){Add(x,v);return;}
	int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
	down(x);
	if(r<=mid)add(lc,l,r,v);
	else if(l>mid)add(rc,l,r,v);
	else add(lc,l,mid,v),add(rc,mid+1,r,v);
	up(x);
}
int go(int x,int k)
{
	if(tr[x].l==tr[x].r)
	{
		if(tr[x].c>=k)return tr[x].l;
		return tr[x].l-1;
	}
	int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
	down(x);
	if(tr[lc].c>=k)return go(rc,k);
	return go(lc,k);
}
int main()
{
	n=read();scanf("%lf",&k);
	for(int i=1;i<=n;i++)
	{
		b[i]=read();
		int t=(int)floor((double)i/k);
		h[t].push_back(i);
	}
	sort(b+1,b+1+n);
	for(int i=1;i<=n;i++)
	{
		if(i==1||b[i]!=b[i-1])cnt++;
		s[cnt]++;to[cnt]=b[i];
	}
	for(int i=cnt-1;i;i--)s[i]+=s[i+1];
	dfs(0);
	build(1,cnt);
	for(int i=1;i<=n;i++)
	{
		if(fa[i]&&!mark[fa[i]])mark[fa[i]]=true,add(1,1,V[fa[i]],sz[fa[i]]-1);
		V[i]=go(1,sz[i]);write(to[V[i]]);
		add(1,1,V[i],-sz[i]);
	}
}

猜你喜欢

转载自blog.csdn.net/baidu_36797646/article/details/88322891