简单权值线段树题.1

送花(过程全在注释里)

题目背景

小明准备给小红送一束花,以表达他对小红的爱意。他在花店看中了一些花,准备用它们包成花束。

题目描述

这些花都很漂亮,每朵花有一个美丽值 W W W,价格为 C C C

小明一开始有一个空的花束,他不断地向里面添加花。他有以下几种操作:

  • 1   W   C 1\ W\ C 1 W C:添加一朵美丽值为 W W W,价格为 C C C 的花。
    如果此前已经加入了相等价格的花,那么这朵花不能加入花束。
  • 2 2 2:删除当前花束里最贵的一朵花。
  • 3 3 3:删除当前花束里最便宜的一朵花。
  • − 1 -1 1:完成添加与删除,开始包装花束。

当花束为空时,忽略操作 2 2 2 3 3 3

请你写一个程序,计算出开始包装花束时,花束中所有花的美丽值的总和,以及小明需要为花束付出的总价格。

输入格式

若干行,每行一个操作,以 − 1 -1 1 结束。

输出格式

一行,两个空格隔开的正整数表示开始包装花束时,花束中所有花的美丽值的总和。以及小明需要为花束付出的总价格。

样例 #1

样例输入 #1

1 1 1
1 2 5
2
1 3 3
3
1 5 2
-1

样例输出 #1

8 5

提示

设操作数为 m m m

  • 对于 20 % 20\% 20% 数据, m ≤ 100 m \le 100 m100 1 ≤ W , C ≤ 1 0 3 1\le W,C\le 10^3 1W,C103
  • 对于全部数据, m ≤ 1 0 5 m \le 10^5 m105 1 ≤ W , C ≤ 1 0 6 1\le W,C\le 10^6 1W,C106
#include<bits/stdc++.h>
using namespace std; 
const int N=1e6+10;
typedef long long ll;
int k,pp,meimei;
struct stu{
	int p,mei;
}tree[N*4];
void pushup(int u){
    tree[u].p=tree[u<<1].p+tree[u<<1|1].p;//左右两子段的区间和(总价格和总美丽值)相加反馈给顶部
    tree[u].mei=tree[u<<1].mei+tree[u<<1|1].mei;
}
void update(int l,int r,int u,int p,int mei){//插入一朵价格为p,美丽值为mei的花
	if(l==r){//到达叶子结点
        if(tree[u].p==p) return;//如果已经有一朵价格为p的花了,则不能加入该花
        tree[u].p=p;//否则更新该点信息
        tree[u].mei=mei;
    }
	else{//未到叶子结点继续折半查找
        int mid=(l+r)>>1;
	    if(p<=mid) update(l,mid,u<<1,p,mei);//查找左子树
	    else update(mid+1,r,u<<1|1,p,mei);//查找右子树
        pushup(u);//对顶部更新
    }
}
void remove(int l,int r,int u,int sign){//删除一朵花
    if(l==r) tree[u]={0,0};//找到该点清空删除
    else{
        int mid=(l+r)>>1;
        if(sign){//sign=1是删除最大值
            if(!tree[u<<1|1].p) remove(l,mid,u<<1,sign); //右区间为空则找左区间
            else remove(mid+1,r,u<<1|1,sign); //否则就找右区间
        }
        else{//sign=0是删除最小值
            if(!tree[u<<1].p) remove(mid+1,r,u<<1|1,sign); //左区间为空则找右区间
            else remove(l,mid,u<<1,sign); //否则就找左区间
        }
        pushup(u);//对顶部更新
    }
}
int main(){
    while(scanf("%d",&k)!=EOF){
        if(k==-1) break;
        if(k==1){
            scanf("%d %d",&meimei,&pp);
            update(1,N,1,pp,meimei);
        }
        else if(tree[1].p==0) continue;
        else if(k==2) remove(1,N,1,1);
        else remove(1,N,1,0);
    }
    cout<<tree[1].mei<<" "<<tree[1].p<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

兔子队列

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值