7.8
(E. Boring Segments)[https://codeforces.com/contest/1519/problem/E]
大意是给定一堆{l,r,w}表示覆盖[l,r]需要w的花费。求能够完全覆盖[1,m-1]的最小的最大花费与最小花费之差。
首先想的是二分,发现不可行。然后发现,当固定最小花费时,随着最小花费的增加,最大花费的最小值不减,因此我们利用这个单调性可以使用双指针算法。指针移动的条件是[1,m-1]这个区间没有被完全覆盖。对于这个扫描我的处理方法是用线段树维护区间最小值,懒标记更新区间加减,这样复杂度就是nlogm
const int N=2000010,M=N*2,mod=1e9+7;
int n,m,k,a[N];
struct Seg{
int l,r,w;
}p[N];
struct Segment_Tree{
struct Node{
int l,r;
int mn,tag;
}tr[N<<2];
void push_up(Node &u,Node &l,Node &r){
u.mn=min(l.mn, r.mn);
}
void push_up(int u){
push_up(tr[u],tr[u<<1],tr[u<<1|1]);
}
void calc(Node &u,int tag){
u.mn += tag;
u.tag += tag;
}
void push_down(int u){
if(tr[u].tag){
calc(tr[u<<1], tr[u].tag);
calc(tr[u<<1|1], tr[u].tag);
}
tr[u].tag=0;
}
void build(int u,int l,int r){
tr[u]={l,r};
if(l==r) return ;
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
push_up(u);
}
void modify(int u,int l,int r,int d){
if(tr[u].l>=l&&tr[u].r<=r){
tr[u].mn+=d;
tr[u].tag+=d;
return ;
}
push_down(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u<<1,l,r,d);
if(r>mid) modify(u<<1|1,l,r,d);
push_up(u);
}
int query(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r){
return tr[u].mn;
}
push_down(u);
int mid=tr[u].l+tr[u].r>>1;
if(r<=mid) return query(u<<1,l,r);
if(l>mid) return query(u<<1|1,l,r);
int ans=1e9;
ans=min({ans, query(u<<1,l,r), query(u<<1|1,l,r)});
return ans;
}
}T;
void solve(){
n=read(),m=read();
T.build(1,1,m);
rep(i,1,n){
p[i].l=read(),p[i].r=read(),p[i].w=read();
}
sort(p+1,p+1+n,[](Seg &A,Seg &B){
return A.w<B.w;
});
int ans=1e9;
T.modify(1,p[1].l, p[1].r-1,1);
for(int i=1,j=1;i<=n;++i){
j=max(j, i);
while(j+1<=n&&T.query(1,1,m-1)==0){
j ++;
T.modify(1,p[j].l, p[j].r-1,1);
}
if(T.query(1,1,m-1)){
// debug(i); debug(j); debug(p[j].w-p[i].w);
ans=min(ans, p[j].w-p[i].w);
}
T.modify(1, p[i].l, p[i].r-1, -1);
}
print(ans);
}