题解 P1986 元旦晚会
在长为 \(n\) 的 0/1 数轴上有 \(n\) 个整点,一开始全部点均为 0。有 \(m\) 个要求,形如 \(l_i,r_i,w_i\),表示 \(l_i\) 到 \(r_i\) 的区间和不小于 \(w_i\)。求最少需要把多少个点变为 1。
显然的贪心结论是:把区间按右端点从小到大排序后,尽可能把 1 靠右设置。
考虑贪心到一个区间 \([l,r]\),现在区间和为 \(k\),目标区间和为 \(w\)。如果现在 \(k<w\),则应当找到一个点 \(i\) 使得,\([i,d]\) 中 0 的个数恰为 \(w-k\),然后把区间 \([i,d]\) 全推平成 1。
考虑需要维护什么:区间和(区间 0 个数可以化为 区间长度-区间和)。
考虑需要支持什么:区间推平。
区间推平类似于区间加,区别主要在于标记的更新把加和操作改为赋值操作,还有就是在标记下传的时候要先判断标记是否为空,空标记就设一个永远不会出现的数就行了(比如本例就是-1)。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long rd(){char ch=getchar();long long x=0,f=1;while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while('0'<=ch && ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
void wr(long long x){if(x<0){putchar('-');x=-x;}if(x>9) wr(x/10);putchar(x%10+'0');}
const long long N=30010,M=5010;
struct Segment_tree{
struct node{long long tag,sum;}t[4*N+10];
long long a[N+10];
#define ls (u<<1)
#define rs (u<<1|1)
void refresh(long long u){t[u].sum=t[ls].sum+t[rs].sum;}
void build(long long u,long long l,long long r){
if(l==r){
t[u].tag=-1;t[u].sum=a[l];
return;
}
long long mid=l+r>>1;
build(ls,l,mid); build(rs,mid+1,r);
refresh(u);
}
void pd(long long u,long long l,long long r){
if(t[u].tag==-1) return;
if(l==r){
t[u].tag=-1;
return;
}
long long mid=l+r>>1;
t[ls].tag=t[u].tag;t[rs].tag=t[u].tag;
t[ls].sum=(mid-l+1)*t[u].tag;t[rs].sum=(r-mid)*t[u].tag;
t[u].tag=-1;
}
void upd(long long u,long long l,long long r,long long x,long long y,long long w){
if(x<=l && r<=y){
t[u].tag=w;
t[u].sum=(r-l+1)*w;
return;
}
long long mid=l+r>>1;
pd(u,l,r);
if(x<=mid) upd(ls,l,mid,x,y,w);
if(mid+1<=y) upd(rs,mid+1,r,x,y,w);
refresh(u);
}
long long query(long long u,long long l,long long r,long long x,long long y){
if(x<=l && r<=y){
return t[u].sum;
}
pd(u,l,r);
long long mid=l+r>>1,res=0;
if(x<=mid) res+=query(ls,l,mid,x,y);
if(mid+1<=y) res+=query(rs,mid+1,r,x,y);
return res;
}
}G;
long long n,m,ans;
struct Toone{long long l,r,w;}b[M+10];
bool cmp(Toone u,Toone v){return u.r<v.r;}
int main(){
long long i,j,u,v,w,k;
long long l,r,mid;
n=rd();m=rd();
for(i=1;i<=m;i++){
b[i].l=rd();b[i].r=rd();b[i].w=rd();
}
sort(b+1,b+m+1,cmp);
for(i=1;i<=m;i++){
u=b[i].l;v=b[i].r;w=b[i].w;
k=G.query(1,1,n,u,v);
if(k<w){
l=u;r=v;
while(l<r){
mid=l+r+1>>1;
if(v-mid+1-G.query(1,1,n,mid,v)>=(w-k)) l=mid;
else r=mid-1;
}
ans+=(v-l+1-G.query(1,1,n,l,v));
G.upd(1,1,n,l,v,1);
}
}
wr(ans),putchar('\n');
return 0;
}