文章目录
- 题目描述
- 解析
- 我的思路
- 代码
- 题解思路
题目描述
解析
我的思路
其实就是线段覆盖的一个变体
贪心的想:
把游客按右端点升序排序
后面的证明就和线段覆盖一样了
如果有两个游客冲突
我们应该选右端点靠右的
因为这样对以后继续在右边出现的游客来说肯定不会更差
然后就是对于能否上车的判断
其实就是一个对区间的修改与最大值查询
就非常自然的想到了线段树
时间复杂度:nlogn
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=3e5+100;
ll ans;
int n,c,k;#define mid ((r+l)>>1)
int mx[4*N],add[4*N];
void Add(int k,int v){add[k]+=v;mx[k]+=v;return;
}
void pushdown(int k){if(add[k]==0) return;Add(k<<1,add[k]);Add(k<<1|1,add[k]);add[k]=0;
}
void change(int k,int l,int r,int x,int y,int v){
// printf("l=%d r=%d x=%d y=%d\n",l,r,x,y);if(x<=l&&r<=y){Add(k,v);return;}pushdown(k);if(x<=mid) change(k<<1,l,mid,x,y,v);if(y>=mid+1) change(k<<1|1,mid+1,r,x,y,v);mx[k]=max(mx[k<<1],mx[k<<1|1]);return;
}
int ask(int k,int l,int r,int x,int y){
// printf("l=%d r=%d x=%d y=%d\n",l,r,x,y);if(x<=l&&r<=y){
// printf("l=%d r=%d res=%d\n",l,r,mx[k]);return mx[k];}pushdown(k);int res=0;if(x<=mid) res=max(res,ask(k<<1,l,mid,x,y));if(y>=mid+1) res=max(res,ask(k<<1|1,mid+1,r,x,y));
// printf("l=%d r=%d res=%d\n",l,r,res);mx[k]=max(mx[k<<1],mx[k<<1|1]);return res;
}struct node{int x,y,num;bool operator < (const node o)const{return y<o.y;}
}p[N];
int main(){scanf("%d%d%d",&k,&n,&c);for(int i=1;i<=k;i++){scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].num);} sort(p+1,p+1+k);for(int i=1;i<=k;i++){int xx=p[i].x,yy=p[i].y,nn=p[i].num;int ad=min(nn,c-ask(1,1,n,xx,yy-1));
// printf("i=%d ad=%d ask=%d\n",i,ad,ask(1,1,n,xx,yy));
// printf("x=%d y=%d ad=%d\n\n",xx,yy-1,ad);ans+=ad;change(1,1,n,xx,yy-1,ad);}printf("%lld",ans);
}
/*
in:
8 15 3
1 5 2
13 14 1
5 8 3
8 14 2
14 15 1
9 12 1
12 15 2
4 6 1
out:10
*/
题解思路
突然想到这道二叉堆的题自己似乎并没有用到二叉堆。。。
于是又看了下题解
大概思路就是:
每到一站,只要没满就让游客上来
如果满了,就强制让目的地最靠后的游客下车
当然,已经到站的下车就行(在这个策略下到站的已经就是堆顶元素)
对于那些没到站就被迫下车的游客,等价于没有让他们上车
这样就不用写线段树了,码量减少许多;而且思路也很妙
小技巧:对于一些由于后续情况而当前不知道是否选择的决策,可以暂时先选上,与更优决策与它冲突时再放弃,这样也就等价与没有选择