ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【洛谷P5044】meetings 会议

2021-07-16 08:01:02  阅读:212  来源: 互联网

标签:lazy qr 洛谷 int P5044 mid ql leq meetings


题目

题目链接:https://www.luogu.com.cn/problem/P5044
有 \(N\) 座山横着排成一行,从左到右编号为从 \(0\) 到 \(N-1\)。山的高度为 \(H_i\)(\(0\leq i\leq N-1\))。每座山的顶上恰好住着一个人。
你打算举行 \(Q\) 个会议,编号为从 \(0\) 到 \(Q-1\)。会议 \(j\)(\(0\leq j\leq Q-1\)) 的参加者为住在从山 \(L_j\) 到山 \(R_j\)(包括 \(L_j\) 和 \(R_j\))上的人(\(0\leq L_j\leq R_j\leq N-1\))。对于该会议,你必须选择某个山 \(x\) 做为会议举办地(\(L_j\leq x\leq R_j\))。举办该会议的成本与你的选择有关,其计算方式如下:

  • 来自每座山 \(y\)(\(L_j\leq y\leq R_j\)) 的参会者的成本,等于在山 \(x\) 和 \(y\) 之间(包含 \(x\) 和 \(y\))的所有山的最大高度。特别地,来自山 \(x\) 的参会者的成本是 \(H_x\),也就是山 \(x\) 的高度。
  • 会议的成本等于其所有参会者的成本之和。

你想要用最低的成本来举办每个会议。
注意,所有的参会者将在每次会议后回到他们自己的山;所以一个会议的成本不会受到先前会议的影响。
\(n,Q\leq 7.5\times 10^5\)。

思路

首先考虑一个朴素的 \(O(n^2)\) dp。设 \(f[l][r]\) 表示区间 \([l,r]\) 内所有人聚到一起的最小代价。找到区间 \([l,r]\) 的最大值 \(mid\),那么有

\[f[l][r]=\min(f[l][mid-1]+a[mid]\times (r-mid+1),f[mid+1][r]+a[mid]\times (mid-l+1)) \]

也就是考虑是最大值左边的人去右边还是右边的人去左边。
我们发现每次转移都和区间里的最大值 \(mid\) 有关,考虑在笛卡尔树上进行 dp。
把每一个询问 \([l,r]\) 拆成两个询问 \([l,mid-1],[mid+1,r]\),其中 \(mid\) 是区间 \([l,r]\) 的最大值。这样的话拆出来的第一个询问一定是笛卡尔树一个节点的后缀,第二个询问一定是笛卡尔树一个节点的前缀。分别求出后可以再直接套用上面的转移式一次求出答案。
我们只讨论拆出来的第二个询问,第一个询问可以把数组全部取反后再跑一次得出。
维护一棵线段树,其中节点 \([i,i]\) 表示在目前 dp 到的笛卡尔树节点内,区间 \([l,i]\) 的 dp 值。其中 \(i\) 被包含在笛卡尔树上 \(mid\) 所代表的区间。
假设我们已经递归处理好 \([l,mid-1]\) 和 \([mid+1,r]\) 了,考虑如何将信息合并到 \([l,r]\) 上。
看回上面的转移式。我们发现,在 \(l\) 固定,\(r\) 不断增大的情况下,\(\min\) 内左边的式子每次增加 \(a[mid]\),右边的式子每次增加的值一定不超过 \(a[mid]\)(增加的一定是右子树的某一个值,根据笛卡尔树的性质,这个值肯定不超过 \(a[mid]\))。所以在当前区间 \([l,r]\) 内,\([l,mid-1]\) 已经在左儿子处计算过了,一定存在一个位置 \(p\),使得 \([mid,p]\) 全都是由 \(\min\) 内左边的式子转移而来,\([p+1,r]\) 全都是由 \(\min\) 内右边的式子转移而来。
所以我们可以通过在线段树上二分来找到这一个位置 \(p\)。只需要维护每一个区间右端点的值即可。
找到这个位置后,\([mid,p]\) 的 dp 值就是覆盖为一个等差数列,\([p+1,r]\) 的 dp 值就是全部加上一个定值。所以我们线段树只需要支持区间覆盖,区间家等差数列,并维护区间右端点的值即可。
注意我们翻转区间后需要保证笛卡尔树的形态不变,由于本题的山的高度可能相同,所以在写 ST 表的时候,翻转后原本的 \(<\) 需要变成 \(\leq\) 来保证笛卡尔树的形态。
时间复杂度 \(O((n+Q)\log n)\)。

代码

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

const int N=750010,LG=20;
int n,Q,ID,a[N],lg[N],st[N][LG];
vector<int> ask[N];

struct node
{
	int l,r;
	ll f[2];
}b[N];

void buildst()
{
	for (int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
	for (int i=1;i<=n;i++) st[i][0]=i;
	for (int i=n;i>=1;i--)
		for (int j=1;i+(1<<j)-1<=n;j++)
			if (ID) st[i][j]=(a[st[i][j-1]]>a[st[i+(1<<j-1)][j-1]]) ? st[i][j-1] : st[i+(1<<j-1)][j-1];
				else st[i][j]=(a[st[i][j-1]]>=a[st[i+(1<<j-1)][j-1]]) ? st[i][j-1] : st[i+(1<<j-1)][j-1];
}

int findmax(int l,int r)
{
	int k=lg[r-l+1];
	if (ID) return (a[st[l][k]]>a[st[r-(1<<k)+1][k]]) ? st[l][k] : st[r-(1<<k)+1][k];
		else return (a[st[l][k]]>=a[st[r-(1<<k)+1][k]]) ? st[l][k] : st[r-(1<<k)+1][k];
}

struct SegTree
{
	ll lazy[N*4][3],val[N*4];
	
	void pushdown(int x,int l,int r)
	{
		if (lazy[x][0])
		{
			lazy[x*2][0]=lazy[x*2+1][0]=1;
			lazy[x*2][1]=lazy[x*2][2]=lazy[x*2+1][1]=lazy[x*2+1][2]=0;
			lazy[x][0]=val[x*2]=val[x*2+1]=0;
		}
		if (lazy[x][1] || lazy[x][2])
		{
			int mid=(l+r)>>1;
			lazy[x*2][1]+=lazy[x][1];
			lazy[x*2][2]+=lazy[x][2];
			val[x*2]+=lazy[x][1]+lazy[x][2]*(mid-l);
			lazy[x*2+1][1]+=lazy[x][1]+lazy[x][2]*(mid-l+1);
			lazy[x*2+1][2]+=lazy[x][2];
			val[x*2+1]+=lazy[x][1]+lazy[x][2]*(r-l);
			lazy[x][1]=lazy[x][2]=0;
		}
	}
	
	void pushup(int x)
	{
		val[x]=val[x*2+1];
	}
	
	void update1(int x,int l,int r,int ql,int qr)
	{
		if (ql>qr) return;
		if (ql<=l && qr>=r)
		{
			lazy[x][0]=1; lazy[x][1]=lazy[x][2]=val[x]=0;
			return;
		}
		pushdown(x,l,r);
		int mid=(l+r)>>1;
		if (ql<=mid) update1(x*2,l,mid,ql,qr);
		if (qr>mid) update1(x*2+1,mid+1,r,ql,qr);
		pushup(x);
	}
	
	void update2(int x,int l,int r,int ql,int qr,ll v1,ll v2)
	{
		if (ql>qr) return;
		if (ql<=l && qr>=r)
		{
			lazy[x][1]+=v1; lazy[x][2]+=v2;
			val[x]+=v1+v2*(r-l);
			return;
		}
		pushdown(x,l,r);
		int mid=(l+r)>>1;
		if (qr<=mid) update2(x*2,l,mid,ql,qr,v1,v2);
		else if (ql>mid) update2(x*2+1,mid+1,r,ql,qr,v1,v2);
		else update2(x*2,l,mid,ql,mid,v1,v2),update2(x*2+1,mid+1,r,mid+1,qr,v1+v2*(mid-ql+1),v2);
		pushup(x);
	}
	
	int query1(int x,int l,int r,int k)
	{
		if (l==r) return val[x];
		pushdown(x,l,r);
		int mid=(l+r)>>1;
		if (k<=mid) return query1(x*2,l,mid,k);
			else return query1(x*2+1,mid+1,r,k);
	}
	
	int query2(int x,int l,int r,int ql,int qr,int qmid,ll res)
	{
		if (l==r)
		{
			if (res+(l-qmid+1)*a[qmid]<val[x]+(qmid-ql+1)*a[qmid]) return l+1;
			return l;
		}
		pushdown(x,l,r);
		int mid=(l+r)>>1;
		if (mid<qmid) return query2(x*2+1,mid+1,r,ql,qr,qmid,res);
		if (mid>qr) return query2(x*2,l,mid,ql,qr,qmid,res);
		ll v1=res+(mid-qmid+1)*a[qmid];
		ll v2=val[x*2]+(qmid-ql+1)*a[qmid];
		if (v1>=v2) return query2(x*2,l,mid,ql,qr,qmid,res);
			else return query2(x*2+1,mid+1,r,ql,qr,qmid,res);
	}
}seg;

void solve(int l,int r)
{
	if (l>r) return;
	int mid=findmax(l,r);
	if (l==r) seg.update2(1,1,n,l,r,a[l],0);
	else
	{
		solve(l,mid-1); solve(mid+1,r);
		ll res=seg.query1(1,1,n,mid-1);
		int p=seg.query2(1,1,n,l,r,mid,res);
		seg.update1(1,1,n,mid,p-1);		
		seg.update2(1,1,n,mid,p-1,res+a[mid],a[mid]);
		seg.update2(1,1,n,p,r,a[mid]*(mid-l+1),0);
	}
	for (int i=0;i<ask[mid].size();i++)
	{
		int j=ask[mid][i];
		b[j].f[1]=seg.query1(1,1,n,b[j].r);
	}
}

void work()
{
	buildst();
	seg.update1(1,1,n,1,n);
	for (int i=1;i<=n;i++) ask[i].clear();
	for (int i=1;i<=Q;i++)
	{
		int p=findmax(b[i].l,b[i].r);
		if (p==b[i].r) continue;
		ask[findmax(p+1,b[i].r)].push_back(i);
	}
	solve(1,n);
}

void rev()
{
	reverse(a+1,a+1+n);
	for (int i=1;i<=Q;i++)
	{
		swap(b[i].l,b[i].r); swap(b[i].f[0],b[i].f[1]);
		b[i].l=n-b[i].l+1; b[i].r=n-b[i].r+1;
	}
}

signed main()
{
	scanf("%lld%lld",&n,&Q);
	for (int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	for (int i=1;i<=Q;i++)
	{
		scanf("%lld%lld",&b[i].l,&b[i].r);
		b[i].l++; b[i].r++;
	}
	ID=0; work(); rev();
	ID=1; work(); rev();
	ID=0; buildst();
	for (int i=1;i<=Q;i++)
	{
		ll f0=b[i].f[0],f1=b[i].f[1];
		int l=b[i].l,r=b[i].r,mid=findmax(l,r);
		cout<<min(f0+(r-mid+1)*a[mid],f1+(mid-l+1)*a[mid])<<"\n";
	}
	return 0;
}

标签:lazy,qr,洛谷,int,P5044,mid,ql,leq,meetings
来源: https://www.cnblogs.com/stoorz/p/15018386.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有