【题解】[省选联考 2023] 火车站

题目传送门

[省选联考 2023]火车站

怎么说呢?

题,很难想象这是省选

本人初三,未参选,VP。

先说一下情况:我 VP 的时候交了三发,第一发没有测大样例,没发现 BUG,喜提 40pts;第二发没有检查代码的初始化,喜提 90pts;第三发 AC 爆切,三发总用时包括思考不超过 20min,可见这题有多水了吧。

但看到题解有说用神奇线段树做的,我还是感觉到自己太蒻了。

思路

看到 n n n 的数据范围,很好想到是线性或带 log ⁡ \log log,但这题肯定和 log ⁡ \log log 无关。

看到区间,要不就是神秘 DS \text{DS} DS 或厉害 DP \text{DP} DP,但想到是 D1T1 \text{D1T1} D1T1 就知道肯定没那么毒瘤。

很容易想到一个接近 O ( n 2 ) O(n^2) O(n2) 的,但果断抛弃。考虑线性做法,我们考虑统计答案前进行预处理。设 r m a x i rmax_i rmaxi 为以 i i i 节点为起点的向右最长的道路端点坐标, l m a x i lmax_i lmaxi 同理。设 p s i ps_i psi 判断 i i i 是否为一条路的左端, p e i pe_i pei 同理。设 s s s x x x 向左延申的最长距离坐标, e e e 同理。

接下来假设以上都维护完毕,考虑如何统计答案。很容易想到,我们要先从 s s s 出发,枚举到 x − 1 x-1 x1,如果当前节点 i i i p s i ps_i psi 为真,那就说明这个点可以作为一个终点站计入答案。然后从 x + 1 x+1 x+1 枚举到 e e e,接下来操作同理。

考虑如何维护以上一堆东西。 s , e s,e s,e 都初始化为 x x x r m a x i rmax_i rmaxi 初始化为 − 1 -1 1 l m a x i lmax_i lmaxi 初始化为 + ∞ +\infty +。可以想到,我们在读入每一条边 ( l i , r i ) (l_i,r_i) (li,ri) 时,判断 x x x 是否在这条路里,如果是的话,那就 s ← min ⁡ ( l i , s ) s\leftarrow\min(l_i,s) smin(li,s) e ← max ⁡ ( r i , e ) e\leftarrow\max(r_i,e) emax(ri,e),同时将 p s l i ← 1 ps_{l_i}\leftarrow1 psli1 p e r i ← 1 pe_{r_i}\leftarrow1 peri1 r m a x l i rmax_{l_i} rmaxli 更新为大值, l m a x r i lmax_{r_i} lmaxri 更新为小值。

但我们发现 s , e s,e s,e 没有维护完整,于是考虑继续维护。从 x → e x\to e xe,对于每个 r m a x i rmax_i rmaxi e e e 都更新大值。 s s s 的维护方式同理。

统计答案的方法上面已经讲完了,于是我们就做完了

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace FastIO{
	inline int read(){
		int x=0,f=1;
		char c=0;
		for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
		for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
		return x*f;
	}
	inline void write(int x){
		if(x<0)x=-x,putchar('-');
		if(x>9)write(x/10);
		putchar(x%10+'0');
	}
	inline void writeLine(int x){
		write(x);
		putchar('\n');
	}
};
using namespace FastIO;
int n,m,x,rmax[200005],lmax[200005],s,e,ans=0;
bool ps[200005],pe[200005];
signed main(){
	n=read(),m=read(),x=read();
	for(int i=1;i<=n;i++)rmax[i]=-1,lmax[i]=0x7fffffff;
	s=x,e=x;
	while(m--){
		int x,y;
		x=read(),y=read();
		if(x<=::x&&y>=::x){
			s=min(x,s);
			e=max(y,e);
		}
		ps[x]=1,pe[y]=1;
		rmax[x]=max(y,rmax[x]);
		lmax[y]=min(x,lmax[y]);
	}
	for(int i=x;i<=e;i++){
		if(rmax[i]!=-1)e=max(rmax[i],e);
	}
	for(int i=x;i>=s;i--){
		if(lmax[i]!=-1)s=min(lmax[i],s);
	}
	for(int i=s;i<x;i++){
		if(ps[i]){
			write(i);
			putchar(' ');
		}
	}
	for(int i=x+1;i<=e;i++){
		if(pe[i]){
			write(i);
			putchar(' ');
		}
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值