URAL2014C之妙用线段树

本文介绍了一种利用线段树数据结构解决特定信用卡消费记录问题的方法。问题背景为小明赚取和花费资金,并使用父亲的信用卡进行消费,但消费记录顺序错乱。通过两种不同的线段树实现方案,解决了记录信用卡使用情况的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目传送门: http://acm.hust.edu.cn/vjudge/contest/128024#problem/C

题意: 题目中的小明呢,会赚钱和花钱,花钱的时候会先花掉自己赚的钱,再去花老爸的信用卡,要注意小明不会存钱进去。现在小明每赚一次钱或者花一次钱,都会写一封信告诉老爸花了多少或者赚了多少,如果是用了老爸的信用卡,老爸就会记下来。但是收到信的顺序和实际小明花钱的顺序是不一样的,现在要我们输出每一次收到信老爸需要记录的信用卡使用信息。

有两种线段树可以做: 第一种: 对于当前的活动,只会影响到后面时间的负债,所以更新的话,就更新从当前时间到最后的这个区间。然后查询的时候只要求出从当前时间到最后的一个最小值,然后和0比较就好,然后我们知道tree[1],一定会是最小的那个值。所以直接比较就好~

但是我的查询不知道为什么写丑了。。样例都过不了。。所以还是直接和tree[1]比较吧。。QAQ

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define lson root*2,l,mid
#define rson root*2+1,mid+1,r
#define ls root*2
#define rs root*2+1
const int MAXN=1000100;
typedef long long ll;
using namespace std;

struct SGT
{
    ll tree[MAXN*4];
    ll lazy[MAXN*4];
    void pushup(int root)
    {
        tree[root]=min(tree[ls],tree[rs]);
    }
    void pushdown(int root,int l,int r)
    {
        tree[ls]+=lazy[root];
        tree[rs]+=lazy[root];
        lazy[ls]+=lazy[root];
        lazy[rs]+=lazy[root];
        lazy[root]=0;
    }
    void update(int root,int l,int r,int ql,int qr,ll x)
    {   
        if(ql<=l&&r<=qr)
        {
            tree[root]+=x;
            lazy[root]+=x;
            return ;
        }
        int mid=(l+r)>>1;
        pushdown(root,l,r);
        if(mid>=ql)
        {

            update(lson,ql,qr,x);
        }
        if(mid<qr)
        {
            update(rson,ql,qr,x);
        }
        pushup(root);
    }
};
SGT sgt;

int main (void)
{
    int t;
    cin>>t;
    while(t--)
    {
        int date,month,hour,mi;
        ll mon;
        scanf("%lld %d.%d %d:%d",&mon,&date,&month,&hour,&mi);
        int po=(month-1)*31*24*60+date*24*60+hour*60+mi;
        //printf("po=%d\n",po);
        sgt.update(1,1,MAXN,po,MAXN,mon);
        printf("%lld\n",sgt.tree[1]>0?0:sgt.tree[1]);
        //printf("%lld\n",sgt.tree[1]>0?0:sgt.query(1,1,MAXN,1,po));
    }
    return 0;
}

第二种:我们构造两棵线段树,对于第一棵,我们来存当前手上还有多少钱。(为了方便,我叫他现金树)

对于第二棵,我们来存信用卡花了多少钱。(为了方便,我叫他欠债树)

然后我们在pushup这里干活。

又由于我们是按照时间来建树的,所以:

如果现金树的左儿子比欠债树的右儿子要大,就说明我们能用钱抵消掉信用卡的债。 于是就有这样的pushup:

tree2[root]=tree2[ls];
tree1[root]=tree1[ls]+tree1[rs]-tree2[rs];

否则,我们就只能用现金树的左儿子来抵消掉欠债树右儿子的一部分。 于是就有这样的pushup:

tree1[root]=tree1[rs];
tree2[root]=tree2[ls]+tree2[rs]-tree1[ls];

要注意的是现金树只有左儿子才能还债。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define lson root*2,l,mid
#define rson root*2+1,mid+1,r
#define ls root*2
#define rs root*2+1
const int MAXN=1000100;
typedef long long ll;
using namespace std;

struct SGT
{
    ll tree1[MAXN*4];
    ll tree2[MAXN*4];
    void pushup(int root)
    {
        if(tree1[ls]>=tree2[rs])
        {           
            tree2[root]=tree2[ls];
            tree1[root]=tree1[ls]+tree1[rs]-tree2[rs];
        }
        else
        {
            tree1[root]=tree1[rs];
            tree2[root]=tree2[ls]+tree2[rs]-tree1[ls];
        }
    }
    void update(int root,int l,int r,int p,ll x)
    {
        if(l==r)
        {
            if(x>0)
            {
                tree1[root]=x;//手上有多少钱
            }
            else
            {
                tree2[root]=-x;//信用卡用了多少
            }
            return ;
        }
        int mid=(l+r)>>1;
        if(mid>=p)
        {
            update(lson,p,x);
        }
        else
        {
            update(rson,p,x);
        }
        pushup(root);
    }
};
SGT sgt;

int main (void)
{
    int t;
    cin>>t;
    while(t--)
    {
        int date,month,hour,mi;
        ll mon;
        scanf("%I64d %d.%d %d:%d",&mon,&date,&month,&hour,&mi);
        int po=(month-1)*31*24*60+date*24*60+hour*60+mi;
        //printf("po=%d\n",po);
        sgt.update(1,1,MAXN,po,mon);
        printf("%I64d\n",-sgt.tree2[1]);
    }
    return 0;
}

所以大牛们能告诉我一下为什么下面这样查询是不对的呢。。QAQ

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define lson root*2,l,mid
#define rson root*2+1,mid+1,r
#define ls root*2
#define rs root*2+1
const int MAXN=1000100;
typedef long long ll;
using namespace std;

struct SGT
{
    ll tree[MAXN*4];
    ll lazy[MAXN*4];
    void pushup(int root)
    {
        tree[root]=min(tree[ls],tree[rs]);
    }
    void pushdown(int root,int l,int r)
    {
        tree[ls]+=lazy[root];
        tree[rs]+=lazy[root];
        lazy[ls]+=lazy[root];
        lazy[rs]+=lazy[root];
        lazy[root]=0;
    }
    void update(int root,int l,int r,int ql,int qr,ll x)
    {   
        if(ql<=l&&r<=qr)
        {
            tree[root]+=x;
            lazy[root]+=x;
            return ;
        }
        int mid=(l+r)>>1;
        pushdown(root,l,r);
        if(mid>=ql)
        {

            update(lson,ql,qr,x);
        }
        if(mid<qr)
        {
            update(rson,ql,qr,x);
        }
        pushup(root);
    }
    ll query(int root,int l,int r,int ql,int qr)
    {
        if(ql<=l&&r<=qr)
        {
            return tree[root];
        }
        pushdown(root,l,r);
        int mid=(l+r)>>1;
        ll ans=0xffffffff;
        if(mid>=ql)
        {
            ans=min(ans,query(lson,ql,qr));
        }
        if(mid<qr)
        {
            ans=min(ans,query(rson,ql,qr));
        }
        return ans;
    }
};
SGT sgt;

int main (void)
{
    int t;
    cin>>t;
    while(t--)
    {
        int date,month,hour,mi;
        ll mon;
        scanf("%lld %d.%d %d:%d",&mon,&date,&month,&hour,&mi);
        int po=(month-1)*31*24*60+date*24*60+hour*60+mi;
        //printf("po=%d\n",po);
        sgt.update(1,1,MAXN,po,MAXN,mon);
        //printf("%I64d\n",sgt.tree[1]>0?0:sgt.tree[1]);
        printf("%lld\n",sgt.query(1,1,MAXN,po,MAXN)>0?0:sgt.query(1,1,MAXN,1,MAXN));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值