1 条题解

  • 0
    @ 2025-8-24 23:16:02

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar A2ure_Sky
    El Psy Kongroo

    搬运于2025-08-24 23:16:02,当前版本为作者最后更新于2025-05-02 16:59:37,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题目大意

    是否能从给定的 kk 条线段 (l,m,r)(l,m,r)按照某种顺序地挑出任意个线段覆盖区间 [1,n][1,n],并满足如下条件:

    后挑出的线段的 mm 不能落在已挑出的线段上。

    数据范围

    1n,k5×1051 \leq n,k \leq 5 \times 10^51lmrn1 \leq l \leq m \leq r \leq n

    题解

    这是一个线段覆盖问题,我们像搭桥一样,先从 11 开始拼接线段,最后拼到 nn,因此按 ll 排序是合理的。

    特别要考虑的是 mm 这个约束,我们首先看看怎样才是合法的拼接。

    考虑两条线段 XXYY,其中 lXlYl_X \leq l_Y

    首先能够拼接的必要条件是 XXYY 相交或相邻,即 rXlY1r_X \geq l_Y - 1

    注意到如果两个线段的 mm 都被对方的区间所覆盖的情况显然无法拼接,那么只有两种情况:

    1. mYm_Y 未被覆盖,此时可以先选 XX 再选 YY

      示例图

        ---·--      X
            ----·-- Y
    

    由图可知需满足: rX[lY1,mY1]r_X \in [l_Y - 1, m_Y - 1]

    1. mXm_X 未被覆盖,此时可以先选 YY 再选 XX

      示例图

        ---·-----  X
              -·-- Y
    

    由图可知需满足: lY[mX+1,rX+1]l_Y \in [m_X + 1, r_X + 1]

    上面两种情况满足其一即可拼接


    于是我们就分析完了拼接的问题,现在问题就好办了。

    ll 从小到大维护已经拼接出的若干个区间 [1,rX][1,r_X],考虑新引入的线段 AA 是否可以拼接上前面的区间,这里可以使用 set 维护 xx

    注意我们并不关心拼接的是哪一个区间而只关心是否能拼上,因为拼接完的区间都是 [1,rA][1,r_A]

    根据前面说的,只要满足两个条件中的一个就可以拼接:

    • 对于前者,我们在 set 上二分出一个满足 rXlY1r_X \geq l_Y - 1 的最小的 rXr_X 并判断是否 mY1\leq m_Y - 1(为了方便可以整体加上一)。
    • 对于后者,我们可以借助树状数组差分的方式维护出区间 [mX+1,rX+1][m_X + 1, r_X + 1],然后单点查询 lYl_Y 是否被覆盖即可。

    于是我们就做完啦!

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5e5+10;
    int n,k;
    struct node{
    	int l,m,r;
    	bool operator < (const node &b) const{
    		return (l!=b.l)?(l<b.l):(r<b.r);
    	}
    }a[N];
    set<int> S;
    int t[N];
    void upd(int x,int y){for(;x<=n+2;x+=x&(-x)) t[x]+=y;}
    int qry(int x){
    	int res=0;
    	for(;x;x-=x&(-x)) res+=t[x];
    	return res;
    }
    void solve(){
    	cin>>n>>k;
    	S.clear();
    	for(int i=1;i<=n+2;i++) t[i]=0;
    	for(int i=1;i<=k;i++) cin>>a[i].l>>a[i].m>>a[i].r;
    	sort(a+1,a+k+1);
    	int ans=0;
    	for(int i=1;i<=k;i++){
    		auto it=S.lower_bound(a[i].l);
    		if(it!=S.end()&&(*it)<=a[i].m||a[i].l==1||qry(a[i].l)){
    			ans=max(ans,a[i].r);
    			S.insert(a[i].r+1);
    			upd(a[i].m+1,1),upd(a[i].r+2,-1);//注意树状数组的值域
    		}
    	}
    	cout<< ( (ans==n) ? "YES\n" : "NO\n");
    }
    int main(){
    	ios::sync_with_stdio(false);
    	cin.tie(0);
    	int T; cin>>T;
    	while(T--) solve();
    	return 0;
    }
    • 1

    信息

    ID
    12245
    时间
    1000ms
    内存
    1000MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者