题目
解法
真的毫无头绪... 一直在想如何按时间顺序 (mathtt{dp}),然后就死了...
不妨换一个角度,令 (dp_i) 为使 ([1,i]) 的居民健康的最小代价。转移有:
[dp_i=min dp_j+c_i (r_j-l_i+1ge |t_i-t_j|)
]
注意 (dp_i) 并不考虑 (i) 后的病毒传染过来的情况,因为这种情况会被后面的 (dp) 值所考虑。
解释一下这个条件:
r_j
------- 段 j
------------ 段 i
l_i
- 若 (t_i>t_j)。在执行 (j) 方案后到执行 (i) 方案前的时间里,会从 (r_j) 开始被感染。
- 若 (t_ile t_j)。在执行 (i) 方案后到执行 (j) 方案前的时间里,会从 (l_i) 开始被感染。因为如果我们需要方案 (j),显然 (l_i) 以左是感染区。
如何优化?本来想用 (mathtt{cdq}) 分治,但仔细想想有个巨大的 ( ext{bug}):用 (mathtt{cdq}) 分治肯定是将 (t) 排序从而去掉绝对值,但 (mathtt{dp}) 根本就不应该按 (t) 来转移啊!
这里有个很 (
m nb) 的转移方式 —— 类 Dijkstra
!
用优先队列存下 (mathtt{dp}) 值来进行转移,那么我们可以直接给转移到的方案进行赋值,这就相当于取 (min) 操作!同时,由于每个方案只被更新一次,我们可以保证线段树中 modify()
函数的时间复杂度。
总时间复杂度大概是 (mathcal O(nlog n))。
代码
#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define print(x,y) write(x),putchar(y)
template <class T> inline T read(const T sample) {
T x=0; int f=1; char s;
while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
return x*f;
}
template <class T> inline void write(const T x) {
if(x<0) return (void) (putchar('-'),write(-x));
if(x>9) write(x/10);
putchar(x%10^48);
}
typedef long long ll;
typedef pair <ll,int> pii;
const int maxn=1e5+5;
const ll inf=1e16;
int n,m;
ll f[maxn];
struct Plan {
int t,l,r,c;
bool operator < (const Plan a) const {
return t<a.t;
}
} p[maxn];
struct Tree {
ll mn[2];
} t[maxn<<2];
priority_queue <pii> q;
void pushUp(int o) {
if(!o) return;
t[o].mn[0]=min(t[o<<1].mn[0],t[o<<1|1].mn[0]);
t[o].mn[1]=min(t[o<<1].mn[1],t[o<<1|1].mn[1]);
}
void init(int o,int l,int r,int pos,ll x,ll y) {
if(l>pos or r<pos) return;
if(l==r) {
t[o].mn[0]=x-y,t[o].mn[1]=x+y;
return;
}
int mid=l+r>>1;
init(o<<1,l,mid,pos,x,y);
init(o<<1|1,mid+1,r,pos,x,y);
pushUp(o);
}
void modify(int o,int l,int r,int L,int R,ll lim,ll dp,bool d) {
if(l>R or r<L or t[o].mn[d]>lim)
return;
if(l==r) {
f[l]=dp+p[l].c,q.push(make_pair(-f[l],l));
t[o].mn[0]=t[o].mn[1]=inf;
return;
}
int mid=l+r>>1;
modify(o<<1,l,mid,L,R,lim,dp,d);
modify(o<<1|1,mid+1,r,L,R,lim,dp,d);
pushUp(o);
}
signed main() {
m=read(9),n=read(9);
for(int i=1;i<=n;++i)
p[i].t=read(9),p[i].l=read(9),
p[i].r=read(9),p[i].c=read(9),
f[i]=inf;
sort(p+1,p+n+1);
for(int i=1;i<=n;++i)
if(p[i].l==1) {
f[i]=p[i].c;
q.push(make_pair(-f[i],i));
init(1,1,n,i,inf,0);
}
else init(1,1,n,i,p[i].l,p[i].t);
while(!q.empty()) {
pii u=q.top(); q.pop();
int x=u.second;
modify(1,1,n,1,x-1,p[x].r-p[x].t+1,f[x],0);
modify(1,1,n,x+1,n,p[x].r+p[x].t+1,f[x],1);
}
ll ans=inf;
for(int i=1;i<=n;++i)
if(p[i].r==m)
ans=min(ans,f[i]);
print(ans==inf?-1:ans,'
');
return 0;
}