Scaffolding 2016ICPC香港现场赛 笛卡尔树+贪心

https://open.kattis.com/problems/scaffolding

学习自https://blog.csdn.net/tianyizhicheng/article/details/107960981

感觉这场题目质量挺高的,中间几题都可做,不过对超高水平队伍应该偏容易了一点,这题题目意思有些问题,不然现场应该是有队过的,感觉最难的是I题(流下了不会构造的泪水),有个关键的点时你撘了一个short竹子以后,必须爬到那上面,补题的时候研究了好久的样例2都想不明白,看了一眼题解以后就会做了。

因为高的位置肯定要最后放,因为你向上爬了以后就下不来了,那么肯定就是从高的位置往低的位置贪心,为了使得高的地方能建到,我们必须先把低的地方搭好。直接建小根堆的笛卡尔树,每次求把当前节点所代表的区间的高度变成父节点所统治的区间的高度,需要f[i]轮带m竹子,且由于这f[i]轮带竹子还可以帮忙解决一些比这高度低的位置的竹子,所以还要记录一个g[i]为带了f[i]轮竹子吧当前区间高度变成h[i]以后还剩多少竹子可以用来搭更低部分的竹子。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=1e5+10;

int n,m,rt;ll ans;
ll a[maxl];
ll f[maxl],g[maxl];
struct node
{
	ll k,val,fa,ls,rs,l,r;
}tr[maxl];

inline int build()
{
	int k;
	for(int i=1;i<=n;i++)
	{
		k=i-1;
		while(tr[k].val>tr[i].val)
			k=tr[k].fa;
		tr[i].fa=k;
		tr[i].ls=tr[k].rs;
		tr[tr[k].rs].fa=i;
		tr[k].rs=i;
	}
	return tr[0].rs;
}

inline void prework()
{
	scanf("%d%d",&n,&m);
	tr[0]={0,0,0,0,0,1,n};
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		tr[i]=node{i,a[i],0,0,0,0,0};
	}
	rt=build();
}

inline void dfs(int k)
{
	tr[k].l=tr[k].r=tr[k].k;
	if(tr[k].ls)
	{
		dfs(tr[k].ls);
		f[k]+=f[tr[k].ls];
		g[k]+=g[tr[k].ls];
		tr[k].l=tr[tr[k].ls].l;
	}
	if(tr[k].rs)
	{
		dfs(tr[k].rs);
		f[k]+=f[tr[k].rs];
		g[k]+=g[tr[k].rs];
		tr[k].r=tr[tr[k].rs].r;
	}
	if(k==0)
		return;
	ll tmp=1ll*(tr[k].r-tr[k].l+1)*(tr[k].val-tr[tr[k].fa].val)-g[k];
	if(tmp<0)
		g[k]=-tmp;
	else
	{
		ll d=tmp/m;
		if(tmp%m!=0) d++;
		f[k]+=d;g[k]=d*m-tmp;
	}
}

inline void mainwork()
{
	dfs(0);
	ans=f[0];
} 

inline void print()
{
	printf("%lld",ans);
}

int main()
{
	prework();
	mainwork();
	print();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/108421040