Gokix

一言(ヒトコト)

关注我

题解 P1986 元旦晚会

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;
}
posted @ 2022-08-31 21:38  Gokix  阅读(42)  评论(0编辑  收藏  举报