Gym 100507C Zhenya moves from parents (线段树)

Zhenya moves from parents

题目链接:

http://acm.hust.edu.cn/vjudge/contest/126546#problem/C

Description


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 ? which is the number of Zhenya’s letters (1 ≤ ? ≤ 100 000). These
letters are listed in the next ? 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 ≤ ? ≤ 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


test answer
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有一张信用卡,每当消费时手上有现金都优先花掉现金,否则就透支信用卡. 他也会赚钱,赚得的钱都是现金并且不会用来还信用卡.
每次消费和赚钱他都会写信给他爸爸,但是信的邮寄顺序和消费时间顺序不一致. 父亲每收到一封信都要推断此时信用卡的透支状况.


题解:


由于赚到的钱不会还卡,那么问题的核心是如何把现金和信用卡统一起来:
考虑赚到的钱,虽然不会还卡,但是在后面的消费中会优先使用现金.
所以赚/花的钱只会影响影响后续的行为,而不会影响之前欠款.


对时间离散化,用线段树维护区间最小值.
每次赚/花钱时更新当前时间点以及以后的时间点.
每次查询整个过程中的最小值,即最大欠款. (最小值大于0时输出0,即无透支)


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#define LL long long
#define eps 1e-8
#define maxn 101000
#define mod 100000007
#define inf 0x3f3f3f3f
#define mid(a,b) ((a+b)>>1)
#define IN freopen("in.txt","r",stdin);
using namespace std;


struct Tree
{
    int left,right;
    LL lazy,mini;
}tree[maxn<<2]; /*四倍大小*/


/*递归建树*/
void build(int i,int left,int right)
{
    tree[i].left=left;
    tree[i].right=right;
    tree[i].lazy=0;

    if(left==right){
        tree[i].mini = 0;
        return ;
    }

    int mid=mid(left,right);

    build(i<<1,left,mid);
    build(i<<1|1,mid+1,right);

    tree[i].mini = min(tree[i<<1].mini, tree[i<<1|1].mini);
}

/*区间修改,标记下传:每当访问到当前结点的子节点时,下传标记*/
void pushdown(int i)
{
    if(tree[i].lazy){
        tree[i<<1].lazy+=tree[i].lazy;
        tree[i<<1|1].lazy+=tree[i].lazy;
        tree[i<<1].mini+=tree[i].lazy;
        tree[i<<1|1].mini+=tree[i].lazy;
        tree[i].lazy=0; /*下传后清零*/
    }
}

/*区间修改,d为改变量*/
void update(int i,int left,int right,LL d)
{
    if(tree[i].left==left&&tree[i].right==right)
    {
        tree[i].mini += d;
        tree[i].lazy += d;
        return ;
    }

    pushdown(i);

    int mid=mid(tree[i].left,tree[i].right);

    if(right<=mid) update(i<<1,left,right,d);
    else if(left>mid) update(i<<1|1,left,right,d);
    else
    {
        update(i<<1,left,mid,d);
        update(i<<1|1,mid+1,right,d);
    }

    tree[i].mini = min(tree[i<<1].mini, tree[i<<1|1].mini);
}

/*区间结果查询*/
LL query(int i,int left,int right)
{
    if(tree[i].left==left&&tree[i].right==right)
        return tree[i].mini;

    pushdown(i);

    int mid=mid(tree[i].left,tree[i].right);

    if(right<=mid) return query(i<<1,left,right);
    else if(left>mid) return query(i<<1|1,left,right);
    else return min(query(i<<1,left,mid),query(i<<1|1,mid+1,right));
}

int n;
int monthly[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
struct node {
    LL money;
    int time;
}rec[maxn];
int t[maxn];

int main(int argc, char const *argv[])
{
    //IN;

    for(int i=1; i<=12; i++)
        monthly[i] += monthly[i-1];

    while(scanf("%d", &n) != EOF)
    {
        for(int i=1; i<=n; i++) {
            scanf("%I64d", &rec[i].money);
            int a,b,c,d;
            scanf("%d.%d %d:%d", &a,&b,&c,&d);
            rec[i].time = (monthly[b-1] + a)*24*60 + c*60 + d;
            t[i] = rec[i].time;
        }
        sort(t+1, t+1+n);

        map<int,int> mymap; mymap.clear();
        for(int i=1; i<=n; i++) {
            mymap.insert(make_pair(t[i], i));
        }

        build(1, 1, n);
        for(int i=1; i<=n; i++) {
            int pos = mymap[rec[i].time];
            update(1, pos, n, rec[i].money);
            LL ans = min(query(1, 1, n), 0LL);
            printf("%I64d\n", ans);
        }
    }

    return 0;
}

转载于:https://www.cnblogs.com/Sunshine-tcf/p/5750654.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值