西雅图
18:14发布
西雅图
18:14发布
8°
东南风 4级
空气质量 无
相对湿度 90%
今天
中雨
6°/11°
周四
中雨
3°/10°
周五
2°/10°

CF1295E Permutation Separation

我的blog

题目链接:CF1295E Permutation Separation

preface

本文版权归博客园,洛谷博客和蒟蒻wjr所有,欢迎转载,但需保留此段声明,并给出原文链接,如有侵权行为,还请不吝啬向博主举报,谢谢合作。

开一波E题闷声发大财

感谢@Karry5307 在考后提供思路

description

给定一个序列p(为1~n的排列),和这个序列每一个数所对应的花费a以及序列的长度n。

取一数1k<n,将p序列分成两个序列,分别是p1,p2,...,pkpk+1,pk+2,...,pn

将两个序列的某些数移到另一个序列使得第一个序列的所有数小于第二个序列的所有数,注意如果其中一组为空,则满足此条件,移动pi的花费是ai

求最小花费

solution

一道裸的线段树

考虑维护ai的前缀和sumi=j=1iai,因为1k<n,所以前缀和sum最多只要维护到an1即可

假设第一个序列的所有数都移到了第二个序列值最小虽然不大可能
答案是sum中的最小值

因为p序列是1~n的排列,所以记posii在序列p中出现的位置

枚举i从1~n

假设将p[posi]最终在第一序列,那么p[pos1],p[pos2],...,,p[posi1],考虑当前对前缀和的修改。

k>=posi时,p[posi]在第一序列,那么不需要费用

k<posi时,p[posi]在第二序列,需要a[posi]的费用移动到第一序列

则将sum1~sumposi1的值分别加上a[posi]

sumposi~sumn1的值分别减去a[posi]

当前策略最小值即当前sum的最小值。

答案即是对所有策略的最小值取最小值

code

#include <cstdio>
#include <algorithm>
#define re register
#define ll long long
#define lc (root<<1)
#define rc (root<<1|1)
using namespace std;
template<typename T>
inline void read(T&x)
{
	x=0;
	char s=(char)getchar();
	bool flag=false;
	while(!(s>='0'&&s<='9'))
	{
		if(s=='-')
			flag=true;
		s=(char)getchar();
	}
	while(s>='0'&&s<='9')
	{
		x=(x<<1)+(x<<3)+s-'0';
		s=(char)getchar();
	}
	if(flag)
		x=(~x)+1;
	return;
}
const int N=2e5+5;
struct Tree
{
	ll minn,lazy;
} tree[N<<2];
ll sum[N];
inline void build(int root,int l,int r)
{
	if(l==r)
	{
		tree[root].minn=sum[l];
		tree[root].lazy=0;
		return;
	}
	int mid=(l+r)>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	tree[root].minn=min(tree[lc].minn,tree[rc].minn);
	return;
}
inline void pushdown(int root)
{
	if(!tree[root].lazy)
		return;
	tree[lc].minn+=tree[root].lazy;
	tree[rc].minn+=tree[root].lazy;
	tree[lc].lazy+=tree[root].lazy;
	tree[rc].lazy+=tree[root].lazy;
	tree[root].lazy=0;
	return;
}
inline void change(int root,int l,int r,int x,int y,int val)
{
	if(r<x||l>y)
		return;
	if(x<=l&&r<=y)
	{
		tree[root].minn+=val;
		tree[root].lazy+=val;
		return;
	}
	int mid=(l+r)>>1;
	pushdown(root);
	change(lc,l,mid,x,y,val);
	change(rc,mid+1,r,x,y,val);
	tree[root].minn=min(tree[lc].minn,tree[rc].minn);
	return;
}
int n,p[N],a[N],pos[N];
ll ans;
int main()
{
	read(n);
	for(re int i=1; i<=n; ++i)
	{
		read(p[i]);
		pos[p[i]]=i;
	}
	for(re int i=1; i<=n; ++i)
	{
		read(a[i]);
		sum[i]=sum[i-1]+a[i];
	}
	build(1,1,n-1);
	ans=tree[1].minn;
	for(re int i=1; i<=n; ++i)
	{
		change(1,1,n-1,1,pos[i]-1,a[pos[i]]);
		change(1,1,n-1,pos[i],n-1,-a[pos[i]]);
//		printf("%d\n",ans);
		ans=min(ans,tree[1].minn);
	}
	printf("%lld\n",ans);
	return 0;
}

作者:蒟蒻wjr
欢迎任何形式的转载,但请务必注明出处。
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。

posted @   蒟蒻wjr  阅读(432)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?

点击右上角即可分享
微信分享提示