LGP7214题解

确实牛逼。

考虑选取所有方案,然后观察横坐标为居民纵坐标为时间的图,会发现感染和未感染之间有一条分界线。

显然会有很多条分界线构成一堵“墙”来区分开感染和未感染。

将斜着的分界线建成边,横着的分界线建成点,如果最左端和最右端连通那么说明有解。

选取方案也能类似考虑。于是只需要考虑如何建边即可。

如果我们以 45度 的方向照一束光,那么横着的分界线就会被投影到边界上。这是一个序列。

很显然如果要连边,那么其中一个端点在投影后的序列上一定要在对方的区间中。

注意到如果满足上述条件,但是对方在自己下方的话是不一定能满足条件的。(\((5,2,5)\to(11,5,10)\))所以边必须是单向的。

并且很显然如果一个点被松弛后就不可能被松弛第二遍。(因为边权是出点的点权),所以一个点只会入堆一遍,复杂度为 \(O(n\log n)\) 而非 \(O(n\log^2n)\)

#include<algorithm>
#include<cstdio>
#include<cctype>
#include<queue>
typedef long long ll;
const int M=1e5+5;
int n,m,T,tot,ID[M],l[M],r[M],t[M],c[M];
int ege,id[M*80],val[M*80],h[M*80];ll d[M*80];
struct Edge{
	int v,nx;
}e[M*200];
inline void Add(const int&u,const int&v){
	e[++ege]=(Edge){v,h[u]};h[u]=ege;
}
struct Node{
	int u;ll d;
	inline bool operator<(const Node&it)const{
		return d>it.d;
	}
};std::priority_queue<Node>q;
namespace init{
	int L[M],R[M];int len,lsh[M<<1];
	inline void Build(const int&u,const int&L=1,const int&R=len){
		id[u]=++tot;if(L==R)return;const int&mid=L+R>>1;Build(u<<1,L,mid);Build(u<<1|1,mid+1,R);
		Add(id[u<<1],id[u]);Add(id[u<<1|1],id[u]);
	}
	inline void Link(const int&u,const int&v,const int&l,const int&r,const int&L=1,const int&R=len){
		if(l>R||L>r)return;if(l<=L&&R<=r)return Add(id[u],v),void();
		const int&mid=L+R>>1;Link(u<<1,v,l,r,L,mid);Link(u<<1|1,v,l,r,mid+1,R);
	}
	inline void link(const int&u,const int&v,const int&x,const int&L=1,const int&R=len){
		if(L==R)return Add(v,id[u]),Add(++tot,id[u]),id[u]=tot,void();
		const int&mid=L+R>>1;x<=mid?link(u<<1,v,x,L,mid):link(u<<1|1,v,x,mid+1,R);
		Add(++tot,id[u]);id[u]=tot;Add(id[u<<1],id[u]);Add(id[u<<1|1],id[u]);
	}
	inline void Solve(const int&n){
		len=0;for(int i=1;i<=n;++i)lsh[++len]=L[i],lsh[++len]=R[i];
		std::sort(lsh+1,lsh+len+1);len=std::unique(lsh+1,lsh+len+1)-lsh-1;++len;Build(1);
		for(int i=1;i<=n;++i){
			L[i]=std::lower_bound(lsh+1,lsh+len+1,L[i])-lsh;
			R[i]=std::lower_bound(lsh+1,lsh+len+1,R[i])-lsh;
		}
		for(int r,l=1;l<=n;l=r){
			r=l;while(r<=n&&t[ID[l]]==t[ID[r]])++r;
			for(int i=l;i<r;++i)Link(1,ID[i],L[ID[i]],R[ID[i]]);for(int i=l;i<r;++i)link(1,ID[i],R[ID[i]]);
		}
	}
}
inline void Dijkstra(){
	for(int i=0;i<=tot;++i)d[i]=1e18;q.push((Node){0,d[0]=0});
	while(!q.empty()){
		const int u=q.top().u;q.pop();
		for(int v,E=h[u];E;E=e[E].nx)if(v=e[E].v,d[u]+val[v]<d[v])q.push((Node){v,d[v]=d[u]+val[v]});
	}
}
inline int read(){
	int n(0);char s;while(!isdigit(s=getchar()));while(n=n*10+(s&15),isdigit(s=getchar()));return n;
}
signed main(){
	n=read();m=read();tot=m;
	for(int i=1;i<=m;++i)t[i]=read(),l[i]=read(),r[i]=read()+1,c[i]=read(),val[i]=c[i],t[i]>T&&(T=t[i]),ID[i]=i;
	for(int i=1;i<=m;++i)init::L[i]=l[i]+(T-t[i]),init::R[i]=r[i]+(T-t[i]);
	std::sort(ID+1,ID+m+1,[&](const int&x,const int&y){return t[x]<t[y];});init::Solve(m);
	for(int i=1;i<=m;++i)init::L[i]=l[i]+t[i],init::R[i]=r[i]+t[i];
	std::sort(ID+1,ID+m+1,[&](const int&x,const int&y){return t[x]>t[y];});init::Solve(m);++tot;
	for(int i=1;i<=m;++i){
		if(l[i]==1)Add(0,i);if(r[i]==n+1)Add(i,tot);
	}
	Dijkstra();printf("%lld",d[tot]==1e18?-1:d[tot]);
}
posted @ 2022-07-14 15:17  Prean  阅读(16)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};