首页 > 其他分享 >P1848 Bookshelf G 题解

P1848 Bookshelf G 题解

时间:2023-08-26 16:50:46浏览次数:45  
标签:return xdtr 题解 ll tr P1848 pushup Bookshelf wz

这是本蒟蒻写的第一篇题解(写不好请指出)

很明显他是一道dp题,因为第i本书放哪里只跟前i-1本树的放法有关系。

我们可以是定义f[i][j]表示放了i本书,最后一层书架是以第j本书开始的。

那么有动态转移方程:

\(f[i][i]=min(f[i-1][j])+hi,w[j]+...+w[i-1]<=L\)

\(f[i][j]=f[i-1][j]+max(0,h[i]-max(h[j],..h[i-1]))\)

\(w[j]+w[j+1]+...+w[i]<=L\)

下面思考优化:

1、可以使用单调栈,求出最小的满足条件的j

2、使用平衡树寻找h[j]~h[i-1]中最后一个大于等于h[i]的数的wz,然后修改wz以后的数

3、构造线段树来优化更新时间O(log n)。线段树要记录:

   last->倒数第二层书架到第一层书架的高度

   now->倒数第一层书架的高度
   
   ans->总高度

上代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=100500,INF=1e17;
ll n,L;
ll hi[N],wi[N];

struct jgt
{
	ll l,r;
	ll key,val;
	ll xb,zdxb;
	ll head;
}tr[N];
ll root,idx;
ll get_node(ll x,ll wz)
{
	tr[++idx].xb=wz;
	tr[idx].zdxb=wz;
	tr[idx].key=x;
	tr[idx].val=rand();
	tr[idx].head=wz;
	return idx;
}
void pushup(ll p)
{
	tr[p].zdxb=max(tr[p].xb,max(tr[tr[p].l].zdxb,tr[tr[p].r].zdxb));
	return ;
}
void yx(ll &p)
{
	ll q=tr[p].l;
	tr[p].l=tr[q].r;
	tr[q].r=p;
	pushup(p);
	p=q;
	pushup(p);
	return ;
}
void zx(ll &p)
{
	ll q=tr[p].r;
	tr[p].r=tr[q].l;
	tr[q].l=p;
	pushup(p);
	p=q;
	pushup(p);
	return ;
}
void add(ll &p,ll x,ll wz)
{
	if(!p)
	{
		p=get_node(x,wz);
		return ;
	}
	if(x<tr[p].key)
	{
		add(tr[p].l,x,wz);
		if(tr[tr[p].l].val>tr[p].val) yx(p);
		pushup(p);
		return ;
	}
	if(x==tr[p].key)
	{
		tr[p].xb=max(tr[p].xb,wz);
		pushup(p);
		return ;
	}
	if(x>tr[p].key)
	{
		add(tr[p].r,x,wz);
		if(tr[tr[p].r].val>tr[p].val) zx(p);
		pushup(p);
		return ;
	}
	return ;
}
void remove(ll &p,ll x,ll wz)
{
	if(!p) return ;
	if(x<tr[p].key)
	{
		remove(tr[p].l,x,wz);
		pushup(p);
		return ;
	}
	if(x>tr[p].key)
	{
		remove(tr[p].r,x,wz);
		pushup(p);
		return ;
	}
	if(x==tr[p].key)
	{
		if(wz!=tr[p].xb) return ;
		if(!tr[p].l&&!tr[p].r)
		{
			p=0;
			pushup(p);
			return ;
		}
		if(!tr[p].r&&tr[tr[p].l].val>tr[tr[p].r].val)
		{
			yx(p);
			remove(tr[p].r,x,wz);
			pushup(p);
			return ;
		}
		else
		{
			zx(p);
			remove(tr[p].l,x,wz);
			pushup(p);
		}
	}
}
ll query(ll p,ll x)
{
	if(!p) return -INF;
	if(x>=tr[p].key) return query(tr[p].r,x);
	return max(query(tr[p].l,x),max(tr[tr[p].r].zdxb,tr[p].xb));
}
//平衡树 
struct jgt1
{
	ll last,now;
	ll ans;
}xdtr[N*8];
void gai(ll wz,ll l,ll r,ll md,ll la,ll no)
{
	if(l==md&&r==md)
	{
		xdtr[wz].last=la;
		xdtr[wz].now=no;
		xdtr[wz].ans=la+no;
		return ;
	}
	ll mid=(l+r)/2;
	if(md<=mid) gai(wz*2,l,mid,md,la,no);
	else gai(wz*2+1,mid+1,r,md,la,no);
	if(xdtr[wz*2].last<xdtr[wz*2+1].last)
	{
		xdtr[wz].last=xdtr[wz*2].last;
		xdtr[wz].now=xdtr[wz*2].now;
	}
	else if(xdtr[wz*2].last==xdtr[wz*2+1].last)
	{
		xdtr[wz].last=xdtr[wz*2].last;
		xdtr[wz].now=min(xdtr[wz*2].now,xdtr[wz*2+1].now);
	}
	else
	{
		xdtr[wz].last=xdtr[wz*2+1].last;
		xdtr[wz].now=xdtr[wz*2+1].now;
	}
	xdtr[wz].ans=min(xdtr[wz*2].ans,xdtr[wz*2+1].ans);
}
ll tag[N*8];
void pushdown(ll wz,ll l,ll r)
{
	tag[wz*2]=tag[wz];
	tag[wz*2+1]=tag[wz];
	xdtr[wz*2].now=tag[wz];
	xdtr[wz*2+1].now=tag[wz];
	xdtr[wz*2].ans=xdtr[wz*2].now+xdtr[wz*2].last;
	xdtr[wz*2+1].ans=xdtr[wz*2+1].now+xdtr[wz*2+1].last;
	tag[wz]=-1;
	return ;
}
void xg(ll wz,ll l,ll r,ll le,ll ri,ll no)
{
	if(tag[wz]!=-1) pushdown(wz,l,r);
	if(le<=l&&ri>=r)
	{
		xdtr[wz].now=no;
		xdtr[wz].ans=xdtr[wz].now+xdtr[wz].last;
		tag[wz]=no;
		return ;
	}
	ll mid=(l+r)/2;
	if(le<=mid) xg(wz*2,l,mid,le,ri,no);
	if(ri>mid) xg(wz*2+1,mid+1,r,le,ri,no);
	if(xdtr[wz*2].last<xdtr[wz*2+1].last)
	{
		xdtr[wz].last=xdtr[wz*2].last;
		xdtr[wz].now=xdtr[wz*2].now;
	}
	else if(xdtr[wz*2].last==xdtr[wz*2+1].last)
	{
		xdtr[wz].last=xdtr[wz*2].last;
		xdtr[wz].now=min(xdtr[wz*2].now,xdtr[wz*2+1].now);
	}
	else
	{
		xdtr[wz].last=xdtr[wz*2+1].last;
		xdtr[wz].now=xdtr[wz*2+1].now;
	}
	xdtr[wz].ans=min(xdtr[wz*2].ans,xdtr[wz*2+1].ans);
}
ll find(ll wz,ll l,ll r,ll le,ll ri)
{
	if(tag[wz]!=-1) pushdown(wz,l,r);
	if(le<=l&&ri>=r) return xdtr[wz].ans;
	ll mid=(l+r)/2,ans=INF;
	if(le<=mid) ans=min(ans,find(wz*2,l,mid,le,ri));
	if(ri>mid) ans=min(ans,find(wz*2+1,mid+1,r,le,ri));
	return ans;
}
//线段树 
ll zz=1,zh;
//指针 
void init()
{
	tr[0].xb=-INF;
	tr[0].zdxb=-INF;
}
//初始化
ll tzy;
//一些无用的tzy 
int main()
{
	memset(tag,-1,sizeof tag);
	init();
	scanf("%lld %lld",&n,&L);
	for(ll i=1;i<=n;i++)
	scanf("%lld %lld",&hi[i],&wi[i]);
	zz=1;
	zh=wi[1];
	add(root,hi[1],1);
	gai(1,1,n,1,0,hi[1]);
	for(ll i=2;i<=n;i++)
	{
		tzy=find(1,1,n,zz,i-1);
		gai(1,1,n,i,tzy,hi[i]);
		zh+=wi[i];
		while(zh>L)
		{
			zh-=wi[zz];
			remove(root,hi[zz],zz);
			zz++;
		}
		tzy=query(root,hi[i]);
		add(root,hi[i],i);
		if(tzy==-INF) tzy=zz-1;
		tzy++;
		if(tzy<=i-1) xg(1,1,n,tzy,i-1,hi[i]);
	}
	printf("%lld\n",find(1,1,n,zz,n));
	return 0;
}

标签:return,xdtr,题解,ll,tr,P1848,pushup,Bookshelf,wz
From: https://www.cnblogs.com/pengchujie/p/17659020.html

相关文章

  • 力扣-228. 汇总区间(C++题解)
    题目链接:https://leetcode.cn/problems/summary-ranges/description/给定一个 无重复元素的 有序整数数组\(nums\)。返回恰好覆盖数组中所有数字的最小有序区间范围列表 。也就是说,\(nums\)的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于\(......
  • P2151 [SDOI2009] HH去散步 题解
    传送门简要题意:有\(n\)个人,\(m\)条无向边,走\(e\)条边,满足条件若第\(i\)条边为\(u->v\)则第\(i+1\)条边不能是\(v->u\),问\(s->t\)的方案有多少个,取模45989。因为要满足题目关于边的条件,所以我们考虑点边互换。将\(u-v\)的无向边一分为二变成\(u->v,v->u\),第\(i\)条边记录两个变......
  • 【题解】CF1413C Perform Easily(双指针)
    【题解】CF1413CPerformEasily写篇题解水水经验~顺便增加一下RP~比较套路和简单的一道绿题。题目链接PerformEasily-洛谷|计算机科学教育新生态(luogu.com.cn)题意概述给你一个长度为\(6\)的\(a\)数组,和一个长度为\(n\)的\(b\)数组,要求将\(b\)数组内的每......
  • [CF1794E] Labeling the Tree with Distances 题解
    [CF1794E]LabelingtheTreewithDistances题解题目描述给你一个树,边权为\(1\)。给定\(n-1\)个数,你需要将这些数分配到\(n-1\)个节点上。一个点\(x\)是好的,当且仅当存在一种分配方案,所有被分配数的点到\(x\)的最短路径长度等于其被分配的数。求所有好点。思路从......
  • 1.2 金字塔原理-构建金字塔原理与问题解决
    一、构建金字塔原理与问题解决1.自上而下2.自下而上3.解决问题的过程界定问题详细描述问题的背景信息用SMART原理定义目标明确想要达到的成果以及衡量成功与否的标准分解问题关键分析以假设和最终结果为导向反复地进行假设和数据分析尽可能地简化分......
  • 网络规划设计师真题解析--IP地址(二)
    地址202.118.37.192/26是(25),地址192.117.17.255/22是(26)。(2018年真题)(25)A.网络地址B.组播地址C.主机地址D.定向广播地址(26)A.网络地址B.组播地址C.主机地址D.定向广播地址答案:(25)A(26)C解析:(25)202.118.37.192/26,建网比特数为/26,前三字节为24位,光看最后一字节192......
  • wmctf的题解&&blindless&&exit_hook
    0x00好久不见2023.8.23夜里wm2023也是一个收获很大的比赛。只做了一个blindless,但是体会到了无泄露做出题来的奥妙。踩过的坑(学到的东西)包括但不限于调试要用docker,不然没符号表很痛苦有想法一定要及时记下来,很有可能是解题重点exit_hook的n种姿势(下面记录一下......
  • P4327题解
    思路分组计算以下图为例:..#...#...*...#...#.#.#.#.*.*.#.#.#.X.#.X.*.X.*.X.#.#.#.#.#.*.*.#.#...#...#...*...#..我们可以发现每个图形的第1、2、4、5排均是同样的图形,可我们仔细观察第3排:#.X.#.X.*.X.*.X.#只有第一个图形是完整的(或者说对称)附图:#......
  • 牛客练习赛114 D题题解
    比赛编号太臭了题目链接对一第一组数据,我们形象化的得到下图:如何拆解使其变成一个“顺子”呢,我们像这样:贪心的从后往前取,对于取数列时的终点也就是枚举的起点如果不为0,就向前一直取,如果取到一个数\(x\)发现这个数的个数\(num_x\)是大于\(num_{x-1}\)的,就停止,最后看拆......
  • P9166题解
    简单题,但是我考场写炸了。\(100\rightarrow70\)。我们读入的时候,先开两个数组\(ls,rs\)来记录当前这个点是否为某条线段左端点或右端点。我们发现,每一条线段都是连续的,因此可以直接差分记录当前这个点能否走到。然后你提交上去发现你能过。实际上这种做法是假的。为什么呢?......