题意:
有个房屋,有种治疗方案。
一开始所有人都得了病。
每种治疗方案给出:。表示第天晚上选择治疗的人花费。
每天早上得病的人都会往左右相邻传染一个。
问把所有人病治好的最小花费。
思路:
治好相当于选择的每个方案能“无缝衔接”。
向能衔接的方案连边。
具体向连边:
- : 即
- : 即
然后可以线段树优化建图跑最短路。复杂度
其实因为最短路更新的点权恒定为,所以跑Dijkstra()每个点只会被松弛一次。
因此建两棵权值与的线段树,每次取出堆顶,在线段树上松弛下一个点,加入堆中。
被松弛的点就可以删去(线段树上权值赋为inf)
具体线段树权值存最小值,代表如果最小值都比当前比较值大那就不用找下去了,这样每一个点只会被更一次,复杂度找到这个点。
代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
const int inf=2e9+6;
struct node {int t,l,r,c;}a[N];
struct seg {int l,r,mn1,mn2;}T[N];
bool cmpT(node u,node v) {return u.t<v.t;}
struct pq {
int p;ll w;
bool operator<(const pq &u) const{return w>u.w;}
};
priority_queue<pq> Q;
int n,m,ls[N],rs[N],nd,tt[N];
void P_up(int x) {T[x].mn1=min(T[ls[x]].mn1,T[rs[x]].mn1);T[x].mn2=min(T[ls[x]].mn2,T[rs[x]].mn2);}
void Build(int &x,int l,int r) {
x=++nd;T[x]=(seg){l,r,inf,inf};
if(l==r) {
if(a[l].l==1)return;
T[x].mn1=a[l].l+a[l].t;T[x].mn2=a[l].l-a[l].t;return;
}
int mid=(l+r)>>1;
Build(ls[x],l,mid),Build(rs[x],mid+1,r);
P_up(x);
}
int up;
ll w;
void _fdL(int x,int p,int q) {
if(T[x].mn2>up) return;
if(T[x].l==T[x].r) {
int k=T[x].l;Q.push((pq){k,w+a[k].c});
// printf("to %d\n",k);
T[x].mn1=T[x].mn2=inf;
return;
}
int mid=(T[x].l+T[x].r)>>1;
if(p<=mid)_fdL(ls[x],p,q);
if(q>mid)_fdL(rs[x],p,q);
P_up(x);
}
void _fdR(int x,int p,int q) {
if(T[x].mn1>up) return;
if(T[x].l==T[x].r) {
int k=T[x].l;Q.push((pq){k,w+a[k].c});
T[x].mn1=T[x].mn2=inf;
return;
}
int mid=(T[x].l+T[x].r)>>1;
if(p<=mid)_fdR(ls[x],p,q);
if(q>mid)_fdR(rs[x],p,q);
P_up(x);
}
void DJ() {
int rt;Build(rt,1,m);
for(int i=1;i<=m;i++) {
if(a[i].l!=1) continue;
Q.push((pq){i,a[i].c});
}
ll ans=1e18;
while(!Q.empty()) {
int u=Q.top().p;w=Q.top().w;Q.pop();
// printf("%d %lld\n",u,w);
if(a[u].r==n) {ans=min(ans,w);continue;}
int k=upper_bound(tt+1,tt+1+m,a[u].t)-tt-1; //the last <=a[u].t
// printf("#k = %d\n",k);
up=a[u].r-a[u].t+1;_fdL(1,1,k);
if(k!=m){up=a[u].r+a[u].t+1;_fdR(1,k+1,m);}
}
printf("%lld",(ans==1e18)?-1:ans);
}
int main() {
// freopen("03-05.in","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {scanf("%d%d%d%d",&a[i].t,&a[i].l,&a[i].r,&a[i].c);}
sort(a+1,a+1+m,cmpT);
// for(int i=1;i<=m;i++)printf("(%d:) t=%d l=%d r=%d c=%d\n",i,a[i].t,a[i].l,a[i].r,a[i].c);
for(int i=1;i<=m;i++) {tt[i]=a[i].t;}
DJ();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人