Loading

P7214 [JOISC2020] 治療計画

P7214 [JOISC2020] 治療計画

我自裁罢,这种题搞了一下午。

看完题面预测是个dp,数据范围几百到几千。看完数据范围人傻了。

根据样例发现 \(l=1\quad or\quad r=n\) 的计划非常特殊,因为这些计划执行完,治愈人数不断减少 \(1\) ,而其他没有与端点相连的计划执行完会减少 \(2\)

发现两个计划要能连起来才有用,不然中间空开一段还是没法治愈(当然,如果中间再加一个计划,三个计划连起来就可能有用了)。而我们的目的就是把一个 \(L_i=1\) 的计划和一个 \(R_j=n\) 的计划连起来,同时最小化代价。

两个计划能连起来,当且仅当

\[L_i\le R_j-|T_i-T_j|+1\\ \Leftrightarrow\\ i<j:\quad L_i-T_i-1\le R_j-T_j\\ i>j:\quad L_i+T_i-1\le R_j+T_j \]

把计划当作点,然后线段树优化连边,跑最短路即可。

这个线段树优化建图有点鬼畜。

所有计划先按照时间排序。

\(2\) 颗线段树维护 \(L_i-T_i-1\)\(L_i+T_i-1\),把这个值拆成 \(\log m\) 段区间丢到线段树上,每一个节点要从小到大排序这些值。

一个结点被松弛之后要直接从线段树删去,多次松弛复杂度会假。

由于要排序还要删除,我偷懒拿set,直接跑成最劣解,不开O2会T飞=_=,别人的常数是我的 1/30。

其实可以用 vector 排序,然后开一个指针扫,常数应该会小很多,然而我懒=_=

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mkp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define sz(v) (int)v.size()
typedef long long LL;
typedef double db;
template<class T>bool ckmax(T&x,T y){return x<y?x=y,1:0;}
template<class T>bool ckmin(T&x,T y){return x>y?x=y,1:0;}
#define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)
#define per(i,x,y) for(int i=x,i##end=y;i>=i##end;--i)
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f?x:-x;
}
const int N=100005;
int n,m;
LL dis[N];
bool vis[N];
struct node{int T,L,R,C;}a[N];
inline bool cmp(const node&a,const node&b){return a.T<b.T;}
priority_queue<pair<LL,int> >pq;
struct SegmentTree{
static const int T=N<<2;
#define lc (p<<1)
#define rc (p<<1|1)
set<pair<int,int> >S[T];
void change(int pos,int val,int l=1,int r=m,int p=1){
	S[p].insert(mkp(val,pos));
	if(l==r)return;
	int mid=(l+r)>>1;
	if(pos<=mid)change(pos,val,l,mid,lc);
	else change(pos,val,mid+1,r,rc);
}
void link(int ql,int qr,int val,LL d,int l=1,int r=m,int p=1){
	if(ql<=l&&r<=qr){
		while(!S[p].empty()){
			set<pair<int,int> >::iterator t=S[p].begin();
			if(t->fi>val)break;
			if(ckmin(dis[t->se],d+a[t->se].C))pq.push(mkp(-dis[t->se],t->se));
			S[p].erase(t);
		}
		return;
	}
	int mid=(l+r)>>1;
	if(ql<=mid)link(ql,qr,val,d,l,mid,lc);
	if(mid<qr)link(ql,qr,val,d,mid+1,r,rc);
}
}T[2];
LL Dij(){
	memset(dis,0x3f,sizeof(dis)),memset(vis,0,sizeof(vis));
	rep(i,1,m)T[0].change(i,a[i].L-a[i].T-1),T[1].change(i,a[i].L+a[i].T-1);
	rep(i,1,m)if(a[i].L==1)pq.push(mkp(-(dis[i]=a[i].C),i));
	while(!pq.empty()){
		int u=pq.top().se;pq.pop();
		if(vis[u])continue;vis[u]=1;
		if(a[u].R==n)return dis[u];
		if(u>1)T[0].link(1,u-1,a[u].R-a[u].T,dis[u]);
		if(u<m)T[1].link(u+1,m,a[u].R+a[u].T,dis[u]);
	}
	return -1;
}
signed main(){
	n=read(),m=read();
	rep(i,1,m)a[i].T=read(),a[i].L=read(),a[i].R=read(),a[i].C=read();
	sort(a+1,a+m+1,cmp),printf("%lld\n",Dij());
	return 0;
}
posted @ 2021-01-05 09:49  zzctommy  阅读(137)  评论(0编辑  收藏  举报