来源:牛客网

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

𝑅𝑒𝑘𝑖在课余会接受一些民间的鹰眼类委托,即远距离的狙击监视防卫。
𝑅𝑒𝑘𝑖一共接到了𝑚份委托,这些委托与𝑛个直线排布的监视点相关。 第𝑖份委托的内容为:对于区间[𝑙𝑖,
𝑟𝑖]中的监视点,至少要防卫其中的𝑘𝑖个。 𝑅𝑒𝑘𝑖必须完成全部委托,并且希望选取尽量少的监视点来防卫。

输入描述:
第一行,两个正整数𝑛,𝑚。
接下来𝑚行,每行三个整数𝑙𝑖,𝑟𝑖,𝑘𝑖。
输出描述:
一行,一个整数,即所需防卫的最少监视点数量。
示例1
输入
复制

11 5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

输出
复制

6

备注:

对于10%的数据,𝑛 ≤ 10。
对于20%的数据,𝑛 ≤ 20。
对于30%的数据,𝑛,𝑚 ≤ 30。
对于60%的数据,𝑛,𝑚 ≤ 1000。
对于100%的数据,𝑛 ≤ 500000,𝑚 ≤ 1000000,𝑙𝑖 ≤ 𝑟𝑖,𝑘𝑖 ≤ 𝑟𝑖−𝑙𝑖+1

题解:

贪心+线段树
我们先将给的m个区间进行排序,按照右端点值从小到大排
然后对每个区间值查询监视点的数量,如果不满足要求就填充,记得要尽可能的给区间的右侧填充,因为这样更有利于后面的区间能用上
比如[1,3]和[3,6],两个区间各需要一个监视点,我们我们给[1,3]按上一个,尽可能在右侧安装,也就是点3,这样查询[3,6]时我们发现已经有了,就不用给[3,6]再安装了
区间修改操作涉及到了线段树
那在线段树区间修改的时候,怎么能先优先更新右侧?
很简单,我们在更新是优先更新右节点

	if(r>mid)
		val=update(id*2+1,mid+1,R,l,r,val);
	if(l<=mid)
		val=update(id*2,L,mid,l,r,val);

代码中是先更新id*2+1即右节点,这样就会优先在右侧填充,如果两个语句反过来,就是优先填充左侧
有两种写法(一种用到pushdown的区间修改,另一种单纯只用到单点修改)对了,每个坐标点只能放置一个监视点。。

代码:

#include<set> 
#include<map> 
#include<stack> 
#include<queue> 
#include<vector> 
#include<string> 
#include<time.h> 
#include<math.h> 
#include<stdio.h> 
#include<iostream> 
#include<string.h> 
#include<stdlib.h> 
#include<algorithm> 
#include<functional> 
using namespace std;                
#define ll long long 
#define inf 1000000000 
#define mod 1000000007 
#define maxn 500005 
#define lowbit(x) (x&-x) 
#define eps 1e-9 
struct node
{
   
	int l,r,k;
}a[maxn*2];
int n,m,sum[maxn*5],lazy[maxn*5];
bool comp(node a,node b)
{
   
	return a.r<b.r;
}
void pushdown(int l,int r,int id)
{
   
	if(lazy[id])
	{
   
		int mid=(l+r)/2;
		lazy[id*2]=1;
		sum[id*2]=mid-l+1;
		lazy[id*2+1]=1;
		sum[id*2+1]=r-mid;
		lazy[id]=0;
	}
}
int update(int id,int L,int R,int l,int r,int val)
{
   
	if(val<=0)
		return 0;
	if(L>=l && R<=r)
	{
   
		if(R-L+1-sum[id]<=val)//需要布置监视点 (即便当前全部布满也不能达到要求)
		{
   
			val-=R-L+1-sum[id];//还需要的监视点 
			lazy[id]=1;
			sum[id]=R-L+1;//全部布满
			return val;//还需要布满的数量 
		}
	}
	pushdown(L,R,id);
	int mid=(L+R)/2;
	if(r>mid)
		val=update(id*2+1,mid+1,R,l,r,val);
	if(l<=mid)
		val=update(id*2,L,mid,l,r,val);
	sum[id]=sum[id*2]+sum[id*2+1];
	return val;
}
int query(int id,int L,int R,int l,int r)
{
   
	if(L>=l && R<=r)
		return sum[id];
	pushdown(L,R,id);
	int mid=(L+R)/2,res=0;
	if(l<=mid)
		res+=query(id*2,L,mid,l,r);
	if(r>mid)
		res+=query(id*2+1,mid+1,R,l,r);
	return res;
}
int main(void)
{
   
	int i;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++)
		scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].k);
	sort(a+1,a+m+1,comp);
	for(i=1;i<=m;i++)
	{
   
		int w=query(1,1,n,a[i].l,a[i].r);
		int w1=query(1,1,n,6,6);
		printf("%d~%d w=%d\n",a[i].l,a[i].r,w);
		//printf("%d~%d w=%d\n",6,6,w1);
		update(1,1,n,a[i].l,a[i].r,a[i].k-w);
	}
	
	printf("%d\n",query(1,1,n,1,n));
	return 0;
}
// 监视任务 运行/限制:898ms/2000ms
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
struct node {
   
	int l, r, k;
	bool operator<(const node& b)const {
   
		return r < b.r;
	}
}a[1000005];
int sum[500005 << 2];
int book[500005];
void pushUp(int root) {
   
	sum[root] = sum[root << 1] + sum[root << 1 | 1];
}
void build(int le, int rig, int root) {
   
	if (le == rig) {
   
		sum[root] = 0;
		return;
	}
	int mid = (le + rig) >> 1;
	build(le,mid,root<<1);
	build(mid+1,rig,root<<1|1);
	pushUp(root);
}
int query(int l, int  r, int le, int rig, int root) {
   
	if (l <= le && r >= rig) {
   
		return sum[root];
	}
	int re = 0;
	int mid = (le + rig) >> 1;
	if (l <= mid) {
   
		re += query(l, r, le,mid,root<<1);
	}
	if (r > mid) {
   
		re += query(l, r, mid+1,rig,root<<1|1);
	}
	return re;
}
void update(int pos, int le, int rig, int root) {
   
	if (le == rig) {
   
		sum[root] = 1;
		return;
	}
	int mid = (le + rig) >> 1;
	if (pos <= mid) {
   
		update(pos, le,mid,root<<1);
	}
	else {
   
		update(pos, mid+1,rig,root<<1|1);
	}
	pushUp(root);
}
int main(){
   
	int n, m, ans;
	while (scanf("%d%d", &n, &m) != EOF) {
   
		ans = 0;
		memset(book, 0, sizeof(book));
		for (int i = 0; i < m; i++) {
   
			scanf("%d%d%d",&a[i].l, &a[i].r, &a[i].k);
		}
		build(1, n, 1);
		sort(a, a + m);
		for (int i = 0; i < m; i++) {
   
			int pos = a[i].r;//区间右边界
			int cnt = query(a[i].l,a[i].r, 1, n, 1);//查询该区间已经被防卫的点的数量
			while (cnt < a[i].k) {
   
				while (book[pos]) pos--;//从右向左找位置加防卫
				book[pos] = 1;
				update(pos, 1, n, 1);
				ans++;
				cnt++;
			}
		}
		printf("%d\n", ans);
	}
    return 0;
}