题目描述
小明准备给小红送一束花,以表达他对小红的爱意。他在花店看中了一些花,准备用它们包成花束。
这些花都很漂亮,每朵花有一个美丽值W,价格为C。
小明一开始有一个空的花束,他不断地向里面添加花。他有以下几种操作:
操作 含义
1 W C 添加一朵美丽值为W,价格为C的花。
3 小明觉得当前花束中最便宜的一朵花太廉价,不适合送给小红,所以删除最便宜的一朵花。
2 小明觉得当前花束中最贵的一朵花太贵,他心疼自己的钱,所以删除最贵的一朵花。
-1 完成添加与删除,开始包装花束
若删除操作时没有花,则跳过删除操作。
如果加入的花朵价格已经与花束中已有花朵价格重复,则这一朵花不能加入花束。
请你帮小明写一个程序,计算出开始包装花束时,花束中所有花的美丽值的总和,以及小明需要为花束付出的总价格。
输入格式
若干行,每行一个操作,以-1结束。
输出格式
一行,两个空格隔开的正整数表示开始包装花束时,花束中所有花的美丽值的总和。以及小明需要为花束付出的总价格。
样例
输入
1 1 1
1 2 5
2
1 3 3
3
1 5 2
-1
输出
8 5
说明/提示
对于20%数据,操作数<=100,1<=W,C<=1000。
对于全部数据,操作数<=100000,1<=W,C<=1000000。
题目分析
这道题我们可以以价格为区间来维护一个权值线段树,权值线段树的节点中包含美丽值的区间和、价格的区间和。
操作有四种:
1:向线段树中加入一朵美丽值为w,价格为c的花。用update函数,将这朵花直接放入即可。
2/3:删除最贵/最便宜的花。因为权值线段树是根据价格的大小放入不同的位置,因此我们进行删除操作时不能用update函数了,要重新写一个remove函数来完成操作。
-1:输出总的美丽值和价格。即为tr[1]中所包含的信息,直接输出即可。
代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#include <iomanip>
#define LL long long
#define PII pair<int,int>
using namespace std;
const int N=1e6+5;
struct Node{
int p,w; //p记录价格的区间和,w记录美丽值的区间和
}tr[N*4];
void pushup(int u)
{
tr[u].p=tr[u<<1].p+tr[u<<1|1].p; //左右两子段的区间和相加即可得到父段的信息
tr[u].w=tr[u<<1].w+tr[u<<1|1].w;
}
void update(int u,int l,int r,int x,int v) //插入一朵价格为x,美丽值为v的花
{
if(l==r)
{
if(tr[u].p==x) return; //如果已经有一朵价格为x的花了,则不能加入该花
tr[u].p=x; //否则跟新该该点信息
tr[u].w=v;
}
else
{
int mid=l+r>>1; //二分查找x的位置
if(x<=mid) update(u<<1,l,mid,x,v);
else update(u<<1|1,mid+1,r,x,v);
pushup(u);
}
}
void remove(int u,int l,int r,int s) //删除一朵花
{
if(l==r) tr[u]={0,0}; //找到该点则删除信息
else
{
int mid=l+r>>1;
if(s) //s=1是删除最大值
{
if(!tr[u<<1|1].p) remove(u<<1,l,mid,s); //右区间为空则找左区间
else remove(u<<1|1,mid+1,r,s); //否则找右区间
}
else //s=0删除最小值
{
if(!tr[u<<1].p) remove(u<<1|1,mid+1,r,s); //同理
else remove(u<<1,l,mid,s);
}
pushup(u); //更新父节点信息
}
}
int main()
{
int op;
while(scanf("%d",&op)!=EOF)
{
if(op==-1) break;
if(op==1)
{
int w,c;
scanf("%d %d",&w,&c);
update(1,1,1e6,c,w);
}
else if(tr[1].p==0) continue; //如果花束为空则跳过该删除操作
else if(op==2) remove(1,1,1e6,1);
else remove(1,1,1e6,0);
}
printf("%d %d\n",tr[1].w,tr[1].p);
return 0;
}