题目

传送门

解法

真的毫无头绪... 一直在想如何按时间顺序 \(\mathtt{dp}\),然后就死了...

不妨换一个角度,令 \(dp_i\) 为使 \([1,i]\) 的居民健康的最小代价。转移有:

\[dp_i=\min dp_j+c_i\ \ \ \ (r_j-l_i+1\ge |t_i-t_j|) \]

注意 \(dp_i\) 并不考虑 \(i\) 后的病毒传染过来的情况,因为这种情况会被后面的 \(dp\) 值所考虑。

解释一下这个条件:

     r_j
------- 段 j
    ------------ 段 i
   l_i
  1. \(t_i>t_j\)。在执行 \(j\) 方案后到执行 \(i\) 方案前的时间里,会从 \(r_j\) 开始被感染。
  2. \(t_i\le t_j\)。在执行 \(i\) 方案后到执行 \(j\) 方案前的时间里,会从 \(l_i\) 开始被感染。因为如果我们需要方案 \(j\),显然 \(l_i\) 以左是感染区。

如何优化?本来想用 \(\mathtt{cdq}\) 分治,但仔细想想有个巨大的 \(\text{bug}\):用 \(\mathtt{cdq}\) 分治肯定是将 \(t\) 排序从而去掉绝对值,但 \(\mathtt{dp}\) 根本就不应该按 \(t\) 来转移啊!

这里有个很 \(\rm nb\) 的转移方式 —— 类 Dijkstra

用优先队列存下 \(\mathtt{dp}\) 值来进行转移,那么我们可以直接给转移到的方案进行赋值,这就相当于取 \(\min\) 操作!同时,由于每个方案只被更新一次,我们可以保证线段树中 modify() 函数的时间复杂度。

总时间复杂度大概\(\mathcal O(n\log 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,'\n');
	return 0;
}
posted on 2021-07-16 12:06  Oxide  阅读(114)  评论(0编辑  收藏  举报