本题一般有两种解法,差分约束/贪心。分析思路不在赘述,有很多大佬博客有讲解。
这里只给出实现代码
算法1
(差分约束) 50ms+
C++ 代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long int
const int MAXN = 50000+10;
const int MAXM = 100000+10;
ll m,ans,head[MAXN],tot,a,b,c,dist[MAXN],vis[MAXN];
struct Edge{
ll next,to,dat;
}edge[MAXM];
void add(ll x,ll y,ll c){
edge[tot].to=y;
edge[tot].dat=c;
edge[tot].next=head[x];
head[x]=tot++;
}
void spfa(ll st) {
memset(dist,-0x3f,sizeof(dist));
memset(vis,0,sizeof(vis));
dist[st]=0;
queue<ll> q;
q.push(st);
vis[st]=true;
while(!q.empty())
{ ll t=q.front();
q.pop();
vis[t]=false;
for(ll i=head[t]; i!=-1; i=edge[i].next)
{
ll j=edge[i].to,w=edge[i].dat;
if(dist[j]<dist[t]+w)
{
dist[j]=dist[t]+w;
if(!vis[j])
{ q.push(j);
vis[j]=true;
}
// path[y]=x;
}
}
}
}
int main(){
memset(head,-1,sizeof(head));
tot=0;
scanf("%lld",&m);
ans=0;
while(m--){
scanf("%lld%lld%lld",&a,&b,&c);
b++;
ans=max(a,ans),ans=max(b,ans);
add(a,b,c);
add(0,a,0),add(0,b,0);
}
for(ll i=1;i<=ans;i++)
add(i,i-1,-1), add(i - 1, i, 0);
spfa(0);
cout<<dist[ans]<<endl;
return 0;
}
算法2
(贪心+线段树) 30ms+
C++ 代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long int
typedef struct Node {
int l, r;
int sum;
int lazy;
}Tree;
Tree tree[50010*4];
void pushdown(int p){
if(tree[p].lazy)
{ tree[p<<1].lazy+=tree[p].lazy;
tree[p<<1|1].lazy+=tree[p].lazy;
tree[p<<1].sum+=tree[p].lazy*(tree[p<<1].r-tree[p<<1].l+1);
tree[p<<1|1].sum+=tree[p].lazy*(tree[p<<1|1].r-tree[p<<1|1].l+1);
tree[p].lazy=0;
}
}
void build(int p, int l, int r){
int mid;
tree[p].l=l;tree[p].r=r;
tree[p].lazy=0;
if(l==r){ tree[p].sum=0; return;}
mid = (l+r)/2;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
}
void change_point(int p, int x, int num)
{ int mid;
if(tree[p].l==tree[p].r){ tree[p].sum=tree[p].sum+num; return ; }
mid = (tree[p].l+tree[p].r)/2;
if(x<=mid) change_point(p<<1, x, num);
else change_point(p<<1|1, x, num);
tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
}
int ask_point(int p,int x)
{ int mid;
if(tree[p].l==tree[p].r)
{ return tree[p].sum;
}
if(tree[p].lazy) pushdown(p);
mid=(tree[p].l+tree[p].r)>>1;
if(x<=mid) return ask_point(p<<1,x);
else return ask_point(p<<1|1,x);
}
void update(int p,int L, int R,int c)
{ int mid;
if(L<=tree[p].l&&R>=tree[p].r)
{ tree[p].lazy+=c;
tree[p].sum+=c*(tree[p].r-tree[p].l+1);
return;
}
pushdown(p);
mid=(tree[p].l+tree[p].r)>>1;
if(L<=mid) update(p<<1,L,R,c);
if(R>mid) update(p<<1|1,L,R,c);
tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
}
int find(int p, int x, int y){
int mid;
if(x<=tree[p].l&&tree[p].r<=y) return tree[p].sum;
pushdown(p);
mid = (tree[p].l+tree[p].r)/2;
if(y<=mid) return find(p<<1, x, y);
if(x>mid) return find(p<<1|1,x,y);
return find(p<<1, x, mid) + find(p<<1|1,mid+1,y);
}
struct no{
int l,r,c;
bool operator < (const no &other) const{
return r<other.r;
}
}node[50010];
int n,maxm;
int main(){
scanf("%d",&n);
maxm=0;
for(int i=0;i<n;i++)
{ scanf("%d%d%d",&node[i].l,&node[i].r,&node[i].c);
maxm=max(maxm,node[i].r);
}
//maxm为最大的r,即线段树右边边界。
sort(node,node+n); //每个区间按r从小到大排序
build(1,1,maxm); //建树
int ans=0;
for(int i=0;i<n;i++)
{ int l=node[i].l,r=node[i].r,c=node[i].c;
int sum=find(1,l,r); //区间[l,r]的和
int m=max(0,c-sum); //m为还差多少满足要求
while(m)
{ if(ask_point(1,r)) //当前点已经为1
{
r--;
}
else { //当前点不为1,则置为1,m--
change_point(1,r,1);
r--;
m--;
ans++;
}
}
}
printf("%d\n",find(1,1,maxm));
return 0;
}