1 条题解

  • 0
    @ 2026-4-30 20:52:15

    题意

    维护一个由非工作日(休息日)构成的区间集合,支持动态查询与更新。每次查询给出一个区间 [l,r][l, r] 和一个参数 kk,需要计算当前与查询区间有交集的所有非工作日区间,并根据 kk 的值决定是否将查询区间本身也加入集合。

    思路

    使用一个按右边界排序的集合(如 C++ 的 set)来存储当前的非工作日区间。每次查询时,找到第一个右边界大于等于查询左边界 ll 的区间,然后不断处理所有与查询区间相交的区间:要么将其完全删除,要么将其不与查询区间重叠的部分重新插入。最后,如果 k=1k = 1,则将查询区间本身也插入集合。在删除区间时,可以同步更新工作日的数量。

    算法步骤

    1. 初始化一个空的集合,按右边界排序,用于存储非工作日区间。
    2. 对于每个查询 (l,r,k)(l, r, k)
      • 在集合中找到第一个右边界 l\ge l 的区间。
      • 循环处理所有与 [l,r][l, r] 相交的区间:
        • 如果当前区间完全被查询区间覆盖,则直接删除。
        • 否则,将当前区间中不与查询区间重叠的部分(左半部分或右半部分)重新插入集合。
        • 在删除或修改区间时,同步更新工作日的总数。
      • 如果 k=1k = 1,则将 [l,r][l, r] 插入集合。
    3. 输出每次查询后的工作日数量。

    复杂度分析

    • 每个区间最多被插入一次、删除一次,每次操作的时间复杂度为 O(logn)O(\log n),其中 nn 是当前集合中的区间数量。
    • 每次查询可能涉及多个相交区间的删除与插入,但由于每个区间只被处理常数次,总时间复杂度为 O(mlogn)O(m \log n),其中 mm 是查询次数。

    代码说明

    • 使用 set 存储区间,按右边界排序,便于快速定位第一个可能相交的区间。
    • 使用迭代器遍历并处理所有相交区间,利用 lower_boundupper_bound 找到起始位置。
    • 在删除区间时,根据区间与查询区间的重叠情况,决定是直接删除还是先截断再重新插入。
    • 工作日数量可以通过总天数减去当前集合中所有区间的总长度来维护,或在删除/插入时动态更新。
    
    #include<bits/stdc++.h>
    #define del(a,i) memset(a,i,sizeof(a))
    #define ll long long
    #define inl inline
    #define il inl void
    #define it inl int
    #define ill inl ll
    #define re register
    #define ri re int
    #define rl re ll
    #define mid ((l+r)>>1)
    #define lowbit(x) (x&(-x))
    #define INF 0x3f3f3f3f
    using namespace std;
    template<class T>il read(T &x){
    	int f=1;char k=getchar();x=0;
    	for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;
    	for(;k>='0'&&k<='9';k=getchar()) x=(x<<3)+(x<<1)+k-'0';
    	x*=f;
    }
    template<class T>il _print(T x){
    	if(x/10) _print(x/10);
    	putchar(x%10+'0');
    }
    template<class T>il print(T x){
    	if(x<0) putchar('-'),x=-x;
    	_print(x);
    }
    ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;}
    it qpow(int x,int m,int mod){
    	int res=1,bas=x%mod;
    	while(m){
    		if(m&1) res=(1ll*res*bas)%mod;
    		bas=(1ll*bas*bas)%mod,m>>=1;
    	}
    	return res%mod;
    }
    const int MAXN = 6e5+5;
    int n,m,s[MAXN],sz,ans;
    struct Node{
    	int l,r,k;
    }node[MAXN>>1];
    #define lc (cur<<1)
    #define rc (cur<<1|1)
    struct Seg_Tree{
    	int sum,val,tag;
    }T[MAXN<<2];
    il pushup(int cur){T[cur].sum=T[lc].sum+T[rc].sum;}
    il pushdown(int cur,int l,int r){
    	if(T[cur].tag==-1) return ;
    	T[lc].tag=T[rc].tag=T[cur].tag;
    	if(T[cur].tag==1) T[lc].sum=T[rc].sum=0;
    	else T[lc].sum=T[lc].val,T[rc].sum=T[rc].val;
    	T[cur].tag=-1;
    }
    il build_tree(int cur,int l,int r){
    	T[cur].tag=-1;
    	if(l==r) return T[cur].sum=T[cur].val=s[l+1]-s[l],void();
    	build_tree(lc,l,mid),build_tree(rc,mid+1,r);
    	pushup(cur),T[cur].val=T[lc].val+T[rc].val;
    }
    il updata(int cur,int l,int r,int L,int R,int k){
    	if(l>=L&&r<=R){
    		T[cur].tag=k;
    		if(k==1) T[cur].sum=0;
    		else T[cur].sum=T[cur].val;
    		return ;
    	}
    	pushdown(cur,l,r);
    	if(mid>=L) updata(lc,l,mid,L,R,k);
    	if(R>mid) updata(rc,mid+1,r,L,R,k);
    	pushup(cur);
    }
    it id(int x){return lower_bound(s+1,s+1+sz,x)-s;}
    int main(){
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	read(n),read(m);
    	for(ri i=1;i<=m;++i){
    		read(node[i].l),read(node[i].r),read(node[i].k);
    		++node[i].r;
    		s[++sz]=node[i].l,s[++sz]=node[i].r;
    	}
    	sort(s+1,s+1+sz),sz=unique(s+1,s+1+sz)-s-1;
    	ans=s[1]-1+n-s[sz]+1;
    	build_tree(1,1,sz-1);
    	for(ri i=1;i<=m;++i){
    		ri x=id(node[i].l),y=id(node[i].r)-1;
    		updata(1,1,sz-1,x,y,node[i].k);
    		print(T[1].sum+ans),puts("");
    	}
    	return 0;
    }
    
    
    
    • 1

    信息

    ID
    6738
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者