URAL - 2014 (巧用线段树)

C - Zhenya moves from parents (巧用线段树)

Zhenya moved from his parents’ home to study in other city. He didn’t take any cash with him, he only took his father’s credit card with zero balance on it. Zhenya succeeds in studies at the University and sometimes makes a little money on the side as a Maths tutor. As he makes his own money he spends only it, and when it is over he uses the credit card. Every time he gets or spends money, he sends a letter to his father, where he puts the following two things.

  1. The date when it took place
  2. The sum of earned or spent money

Every time receiving a letter from Zhenya, his father calculates the debt on the credit card at the moment. But here a problem arises. The point is that Russian Post delivers letters in an order different to the one they were sent in.

For example, in the first Zhenya’s letter the father read that on September 10 Zhenya spent one thousand rubles. He thought that his son had used the credit card, and now the debt is one thousand rubles. However the next day came a letter with the information that on September 9 Zhenya earned five hundred rubles. It means that half of the money he spent on September 10 was his own, and the debt on the credit card is just five hundred rubles.

Help Zhenya’s father with his account management.

Input

The first line contains an integer n which is the number of Zhenya’s letters (1 ≤n ≤ 100 000). These letters are listed in the next n lines. Description of each letter consists of the amount of money Zhenya spent or earned (in the form -c or +c accordingly, where c is an integer, 1 ≤ c ≤ 50 000) followed by both date and time when it took place (in the form of dd.MM hh:mm). All dates belong to the same year, which is not leap (i. e. there are 365 days in it). Any two letters contain either different dates or different time. The letters are listed in the order the father received them.

Output

After each received letter output what Zhenya’s father thinks the amount of the debt on the credit card is.

Example

inputoutput
5
-1000 10.09 21:00
+500 09.09 14:00
+1000 02.09 00:00
-1000 17.09 21:00
+500 18.09 13:00
-1000
-500
0
-500
-500

 

题意:Zhenya上大学时使用他爸给的信用卡,同时他也打工赚一些钱,他每次有收支都会给他爸爸寄一封信,内容是收入/支出多少钱,以及这次收支的时间。当Zhenya手头有自己赚的钱时,他会使用那些钱,其他时候他会使用信用卡。问题是邮政系统有问题,他爸爸收到信的时间并不按照收支发生的时间先后顺序,他爸爸想在每次收到一封信的时候根据当前信息判断信用卡欠费多少,所以有时会出现他爸第一天收到一封10号支出100的信,认为自己信用卡要还100,第二天又收到一封告诉他9号赚了100,这时他就认为自己信用卡不用还钱。

 

思路:先建一颗空树,维护手里的钱mon和银行卡里欠的钱cre,然后父亲每次收到一封信就更新那一个点,一直更新到根节点输出根节点的cre值。建树的过程是先将时间化成分钟,然后离散化到1~n,按照离散化后的时间为节点建树。

 

代码:

#include <bits/stdc++.h>
#define mid (left+right)/2
#define lson node*2,left,mid
#define rson node*2+1,mid+1,right

using namespace std;

const int maxn = 4e5+100;
typedef long long ll;

struct node {
    ll mon,cre; // 当前点手里剩余的钱,当前点银行卡里负的钱
} tree[maxn];

struct node2 {
    ll id,date,time;
} a[maxn];

bool cmp1( node2 a, node2 b )
{
    return a.time<b.time;
}

bool cmp2( node2 a, node2 b )
{
    return a.id<b.id;
}

void built( ll node, ll left, ll right ) // 建一颗空树,只存编号的位置,不存具体的值
{
    if ( left==right ) {
        tree[node].mon = tree[node].cre = 0;
        return ;
    }
    built(lson);
    built(rson);
    tree[node].mon = tree[node].cre = 0;
}

void add( ll node, ll left, ll right, ll id, ll date ) 
{
    if ( left==right ) {
        if ( date<0 ) {
            tree[node].cre = date;
        }
        else {
            tree[node].mon = date;
        }
        return ;
    }
    if ( id<=mid ) {
        add(lson,id,date);
    }
    else {
        add(rson,id,date);
    }
    // 左儿子(时间靠前)手里剩的钱可以还右儿子(时间靠后)花的钱
    if ( tree[node*2].mon + tree[node*2+1].cre >= 0 ) { 
        tree[node].cre = tree[node*2].cre;  
        tree[node].mon = tree[node*2].mon+tree[node*2+1].mon + tree[node*2+1].cre;
    }
    else {
        tree[node].cre = tree[node*2].cre + tree[node*2].mon + tree[node*2+1].cre;
        tree[node].mon = tree[node*2+1].mon;
    }
}

int main()
{
    ll i,n,m,d,h,mi;
    scanf("%lld",&n);
    for ( i=1; i<=n; i++ ) {
        scanf("%lld %lld.%lld %lld:%lld",&a[i].date,&m,&d,&h,&mi);
        a[i].time = (m+d*31)*24*60 + (h*60+mi);
        a[i].id = i;
    }
    sort(a+1,a+1+n,cmp1); // 按时间排序
    for ( i=1; i<=n; i++ ) { // 将时间离散化
        a[i].time = i;
    }
    sort(a+1,a+1+n,cmp2); // 恢复开始的顺序
    built(1,1,n);  // 按离散化后的时间建树,时间就是节点编号

    for ( i=1; i<=n; i++ ) {
        add( 1,1,n,a[i].time,a[i].date ); // 每次询问更新一个点
        printf("%lld\n",tree[1].cre);
    }

    return 0;
}

 

题意来源:https://blog.csdn.net/u014610925/article/details/40454359

思路代码来源:https://blog.csdn.net/qq_31617881/article/details/98783210

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值