CF1842E Tenzing and Triangle - 线段树优化 dp -
题目链接:https://codeforces.com/contest/1842/problem/E
题解:
首先,如果两个等腰三角形相交了,那答案肯定不会更优。因此不会相交。
先考虑一个 的 dp:
设 表示考虑到 时的最小代价,首先可以先都加一个 ,这样只需要考虑三角形覆盖范围内的 减去即可。
,其中 表示这两个坐标所确定的等腰直角三角形内部的 之和,减是因为最后要加一个
转移的时候,可以每次更新一下 的
如何优化?首先,为了方便,令 ,具体是将后缀和转化为前缀和,详细见后。这样,覆盖所需要的等腰三角形就变成了
修改一下 dp 的定义:令 表示考虑覆盖到 时的最小代价
考虑一下一个点 会对哪些 dp 值产生贡献?显然是 (也就是说,当 由 转移过来时, 都要加上 点的贡献)
理解的话可以回到 的含义没有变的时候
这就是一个前缀加。利用线段树维护一下 ,然后就是前缀和,区间 min。注意线段树下标要从 0 开始。
最后加上 即可
// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back
using namespace std;
typedef long long ll;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2e5+5;
int n,k,coef;
vector<pii>p[maxn];
ll f[maxn];
struct segm{
ll mn,lazy;
}se[maxn << 2];
void build(int l,int r,int num){
se[num].mn = 1e18;
se[num].lazy = 0;
if(l == r){
return ;
}
int mid=l+r>>1;
build(l,mid,num << 1);build(mid+1,r,num<<1|1);
}
void pushdown(int num,int l,int r){
if(!se[num].lazy)return ;
int mid=r-l+1;
ll lz = se[num].lazy;
se[num << 1].mn += lz, se[num << 1|1].mn += lz;
se[num << 1].lazy += lz, se[num << 1|1].lazy += lz;
se[num].lazy = 0;
}
void update(int l,int r,int x,ll to,int num){
if(r <= x){
se[num].mn += to;
se[num].lazy += to;
return ;
}
pushdown(num,l,r);
int mid = l+r>>1;
if(x <= mid)update(l,mid,x,to,num << 1);
else update(l,mid,x,to,num << 1), update(mid+1,r,x,to,num << 1|1);
se[num].mn = min(se[num << 1].mn, se[num << 1|1].mn);
}
void upd(int l,int r,int x,ll to,int num){
if(l == r){
se[num].mn = to;
return ;
}
pushdown(num,l,r);
int mid = l+r>>1;
if(x <= mid)upd(l,mid,x,to,num << 1);
else upd(mid+1,r,x,to,num << 1|1);
se[num].mn = min(se[num << 1].mn, se[num << 1|1].mn);
}
ll query(int l,int r,int x,int y,int num){
if(x <=l && r<=y)return se[num].mn;
int mid = l+r>>1;
pushdown(num,l,r);
if(y<=mid)return query(l,mid,x,y,num<<1);
else if(x>mid)return query(mid+1,r,x,y,num<<1|1);
else return min(query(l,mid,x,y,num<<1),query(mid+1,r,x,y,num<<1|1));
}
signed main(){
scanf("%d%d%d",&n,&k,&coef);
ll bs = 0;
for(int i=1;i<=n;i++){
int x,y,c;scanf("%d%d%d",&x,&y,&c);
y = k-y;
p[y].pb(mpr(x, c));
bs += c;
}
build(0,k,1);
upd(0,k,0,0,1);
for(int i=1;i<=k;i++){
for(auto it : p[i]){
int y = it.first;
ll c = it.second;
update(0,k,y,-c,1);
}
f[i] = min(query(0,k,0,i-1,1) + 1ll*i*coef, f[i-1]);
upd(0,k,i,f[i]-1ll*i*coef,1);
}
printf("%lld\n",f[k] + bs);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示