集市班车
Description
逛逛集市,兑兑奖品,看看节目对农夫约翰来说不算什么,可是他的奶牛们非常缺乏锻炼——如果要逛完一整天的集市,他们一定会筋疲力尽的。所以为了让奶牛们也能愉快地逛集市,约翰准备让奶牛们在集市上以车代步。但是,约翰木有钱,他租来的班车只能在集市上沿直线跑一次,而且只能停靠N 个地点(所有地点都以1到N之间的一个数字来表示)。现在奶牛们分成K 个小组,第 i 组有Mi (1 ≤ Mi ≤ N)头奶牛,他们希望从Si跑到Ti (1 ≤ Si < Ti ≤ N)。由于班车容量有限,可能载不下所有想乘车的奶牛们,此时也允许小组里的一部分奶牛分开乘坐班车。约翰经过调查得知班车的容量是C ,请你帮助约翰计划一个尽可能满足更多奶牛愿望的方案。
Input
第一行:包括三个整数:K,N和C,彼此用空格隔开。
第二行到K + 1行:在第i + 1行,将会告诉你第i组奶牛的信息:Si,Ei和Mi,彼此用空格隔开。
Output
可以坐班车的奶牛的最大头数
Sample Input
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
Sample Output
10
思路:
以右端点排序后利用线段树维护[l,r]区间中最多可以上几头牛
即query[l,r]中的最大值
void build(int L,int R,int p){
tree[p].l=L,tree[p].r=R;
if(L==R){tree[p].sum=0;return;}
int mid=(L+R)/2;
build(L,mid,2*p);build(mid+1,R,2*p+1);
tree[p].sum=tree[2*p].sum+tree[2*p+1].sum;
}
void down(int p){
tree[2*p].add+=tree[p].add;
tree[2*p].sum+=tree[p].add;;
tree[2*p+1].add+=tree[p].add;
tree[2*p+1].sum+=tree[p].add;
tree[p].add=0;
}
void update(int l,int r,int c,int p){
if(tree[p].add)down(p);
if(r<tree[p].l||l>tree[p].r)return;
if(l<=tree[p].l&&r>=tree[p].r){
tree[p].add+=c;
tree[p].sum+=c;
return;
}
update(l,r,c,2*p);
update(l,r,c,2*p+1);
tree[p].sum=max(tree[p*2].sum,tree[2*p+1].sum);
}
int query(int l,int r,int p){
if(tree[p].add)down(p);
if(l==tree[p].l&&tree[p].r==r)return tree[p].sum;
int mid=(tree[p].l+tree[p].r)/2;
if(r<=mid)return query(l,r,2*p);
if(mid<l)return query(l,r,2*p+1);
return max(query(l,mid,2*p),query(mid+1,r,2*p+1));
}
int main(){
scanf("%d%d%d",&n,&m,&v);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&s[i].l,&s[i].r,&s[i].sum);
build(1,m,1);
sort(s+1,s+1+n,cmp);//右端点排序
for(int i=1;i<=n;i++){
int l=s[i].l,r=s[i].r,sum=s[i].sum;
int res=min(v-query(l+1,r,1),s[i].sum);
update(l+1,r,res,1);
ans+=res;
}printf("%d",ans);
return 0;
}