Linear Kingdom Races

题目链接

就拿此题来唤起我四年前的线段树优化残存的记忆吧


首先先考虑n2算法:

f[i]表示1 i能获得的最大利润

f[i]=maxf[j]cost(j+1,i)+val(j+1,i),其中cost(i,j)表示修好[i,j]需要的花费,val(i,j)表示修好[i,j]的所有路能获得的收益

其中1<=j<i


n方算法时间主要花费在枚举j点,找出最大值,考虑维护c[j]=f[j]cost(j+1,i)+val(j+1,i)其中i为当前枚举到的位置

由于每到一个新的i,需要更新前面某些区间的所有c[j],以及转移是找到c[j]的最大值,因此考虑用线段树维护,每次转移以及修改时间复杂度降低为logn


具体细节:

cost(j+1,i)的更新:每次到一个新的点,之前的每个c[j]里面的cost都是(j+1,i1),因此c[j]需要减去a[i],a[i]为修当前的路的花费

val(j+1,i)的更新:每次到一个新的点,如果该点是某个区间的右端点,记这个区间为(l,i),那么对于c[1 l1],val(j+1,i)就应该加上这个区间的收益

某些小细节在代码里体现了,可以仔细琢磨

点击查看代码
#include<bits/stdc++.h>
#include<vector>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 200007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Tree
{
	int l,r,mx;
	int tag_add;
}tr[N<<2];
int T=1,n,m,x,y;
int a[N];
vector<pair<int,int>> g[N];
inline int Read()
{
	char ch=getchar();bool f=0;int x=0;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')f=1;
	for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
	if(f==1)x=-x;return x;
}
void Pushup(int now)
{
	tr[now].mx=max(tr[now<<1].mx,tr[now<<1|1].mx);
}
void Pushdown(int now)
{
	if(tr[now].tag_add)
	{
		tr[now<<1].tag_add+=tr[now].tag_add;
		tr[now<<1|1].tag_add+=tr[now].tag_add;
		tr[now<<1].mx+=tr[now].tag_add;
		tr[now<<1|1].mx+=tr[now].tag_add;
		tr[now].tag_add=0;
	 } 
}
void Add(int now,int l,int r,int ll,int rr,int val)
{
	if(ll<=l&&r<=rr)
	{
		tr[now].tag_add+=val;
		tr[now].mx+=val;
		return;
	}
	int mid=l+((r-l)>>1);
	Pushdown(now);
	if(ll<=mid)
		Add(now<<1,l,mid,ll,rr,val);
	if(rr>mid) 
		Add(now<<1|1,mid+1,r,ll,rr,val);
	Pushup(now);
}
bool Solve()
{
 	//freopen("test.in","r",stdin);
 	n=Read(),m=Read();
 	for(int i=1;i<=n;++i)
 		a[i]=Read();
	for(int i=1;i<=m;++i)
	{
	 	int in1,in2,in3;
	 	in1=Read(),in2=Read(),in3=Read(); 
	 	g[in2].push_back(make_pair(in1,in3));
	}
	int ans=0;
	for(int i=1;i<=n;++i)
	{
		Add(1,0,n,0,i-1,-a[i]);
		for(auto j=g[i].begin();j!=g[i].end();++j)
			Add(1,0,n,0,j->first-1,j->second);
		ans=max(ans,tr[1].mx);
		Add(1,0,n,i,i,ans);
		//printf("%I64d ",ans);
	}
	cout<<ans<<endl;
	return true;
}
signed main()
{
	//scanf("%lld",&T);
	while(T--)
		if(!Solve())
			printf("-1\n");
	return 0;
}
/*
-std=c++11
-std=c99
*/


posted @   模拟退火  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示