Linear Kingdom Races
题目链接
就拿此题来唤起我四年前的线段树优化残存的记忆吧
首先先考虑\(n^2\)算法:
设\(f[i]\)表示\(1~i\)能获得的最大利润
则\(f[i]=max{f[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,i-1)\),因此\(c[j]\)需要减去\(a[i]\),\(a[i]\)为修当前的路的花费
\(val(j+1,i)\)的更新:每次到一个新的点,如果该点是某个区间的右端点,记这个区间为\((l,i)\),那么对于\(c[1~l-1]\),\(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
*/