2020牛客NOIP(第二场)D

暴力做法

在网格图上,以(x , y) 代表在y时刻,在第x个位置
那么很显然,你把关闭的闸门在图上表示出来就可以了
复杂度 O ( n ∗ m a x ( C ) ) O(n * max(C)) O(nmax(C))

正解做法

发现暴力做法的瓶颈在于 m a x ( C ) max(C) max(C)上,考虑怎么搞掉

于是大胆的猜想,跟缝有没有关系

我们可以用跑最短路的思想来处理
对于两个相邻的缝 ,能否到达对方(非常容易判断,不再赘述)
那么直接按照堆优化的disjkra跑一下就可以了
复杂度 O ( m ∗ l o g m ) O(m * logm) O(mlogm)

#include<bits/stdc++.h>
#define MAXN 200005
typedef long long ll;
using namespace std;

int n,m;
ll ans,tot,vis[MAXN],f[MAXN];

struct node{ll dx,L,R,val,id;}t[MAXN];
struct node2{ll id,val;};
vector<node>ycl[MAXN];
vector<int>ycl2[MAXN];
bool cmp(node x , node y){return x.L < y.L;}
bool cmp2(node x , node y){
	if(x.R == y.R){
		if(x.L == y.L)return x.dx < y.dx;
		return x.L < y.L;	
	}
	return x.R < y.R;
}
bool operator < (node2 x , node2 y){return x.val > y.val;}
priority_queue<node2>q2;


int main(){
	cin>>n>>m;ll a,b,c;ans = 0x3f3f3f3f3f3f;
	for(int i = 1 ; i <= m ; i++){
		cin>>a>>b>>c;
		ycl[a].push_back((node){a , b , c , 0 , 0});
	}
	for(int i = 1 ; i <= n ; i++)sort(ycl[i].begin() , ycl[i].end() , cmp);
	ll last = 0 , zz;
	for(int i = 1 ; i <= n + 1 ; i++){
		zz = ycl[i].size();
		if(zz == 0){
			tot++ , t[tot].dx = i;
			t[tot].L = 0 , t[tot].R = 0x3f3f3f3f3f3f;
			continue;
		}
		last = 0;
		for(int j = 0 ; j < zz ; j++){
			tot++ , t[tot].dx = i;
			t[tot].L = last , t[tot].R = ycl[i][j].L - 1;
			last = ycl[i][j].R + 1;
		}
		tot++ , t[tot].dx = i;
		t[tot].L = last , t[tot].R = 0x3f3f3f3f3f3f;
	}
	memset(f , 0x3f , sizeof(f));
	sort(t + 1 , t + 1 + tot , cmp2);
	t[0].L = 0 , t[0].R = 0x3f3f3f3f3f3f , t[0].dx = 0 , t[0].val = f[0] = 0;
	tot++ , t[tot].L = 0 , t[tot].R = 0x3f3f3f3f , t[tot].dx = n + 1 , t[tot].val = f[tot] = 0x3f3f3f3f3f3f;
	for(int i = 0 ; i <= tot ; i++)ycl2[t[i].dx].push_back(i);
	q2.push((node2){0 , 0});
	node2 now;ll zz2,pp;
	while(!q2.empty()){
		now = q2.top();q2.pop();
		if(vis[now.id])continue;
		vis[now.id] = 1;
		if(t[now.id].dx > 0){
			zz2 = ycl2[t[now.id].dx - 1].size();
			for(int i = 0 ; i < zz2 ; i++){
				pp = ycl2[t[now.id].dx - 1][i];
				if(abs(t[now.id].dx - t[pp].dx) != 1)continue;
				if(t[now.id].L + 1 > t[pp].R)continue;
				if(t[now.id].R + 1 < t[pp].L)continue;
				if(now.val + 1 > t[pp].R)continue;
				zz = max(f[now.id] + 1 , t[pp].L);
				if(zz >= f[pp])continue;
				f[pp] = zz;
				q2.push((node2){pp , f[pp]});
			}
		}
		if(t[now.id].dx < n + 1){
			zz2 = ycl2[t[now.id].dx + 1].size();
			for(int i = 0 ; i < zz2 ; i++){
				pp = ycl2[t[now.id].dx + 1][i];
				if(abs(t[now.id].dx - t[pp].dx) != 1)continue;
				if(t[now.id].L + 1 > t[pp].R)continue;
				if(t[now.id].R + 1 < t[pp].L)continue;
				if(now.val + 1 > t[pp].R)continue;
				zz = max(f[now.id] + 1 , t[pp].L);
				if(zz >= f[pp])continue;
				f[pp] = zz;
				q2.push((node2){pp , f[pp]});
			}
		}
	}
	if(f[tot] >= 0x3f3f3f3f3f)cout<<-1<<endl;
	else cout<<f[tot]<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值