题目传送门
怎么说呢?
大水题,很难想象这是省选。
本人初三,未参选,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 x−1,如果当前节点 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) s←min(li,s), e ← max ( r i , e ) e\leftarrow\max(r_i,e) e←max(ri,e),同时将 p s l i ← 1 ps_{l_i}\leftarrow1 psli←1, p e r i ← 1 pe_{r_i}\leftarrow1 peri←1, 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 x→e,对于每个 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;
}