URAL_2014_Zhenya moves from parents_线段树

我喜欢上了一个女孩,她的名字叫静静,我很想她。


题意:

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

Zhenya爸爸收到了n封信,每次收到一封信都要求输出他认为自己欠费多少。



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.


每次收入只会影响它之后的点,如果影响完所有它后面的点,仍为正,则没有作用。

一共n次操作,如果每次朴素更新,也要花O(N),TLE稳稳的。

可以用线段树来更新,通过递推关系来进行区间的更新。

将时间按分钟转化为点,建线段树,对线段树的每个点,维护sum表示该段的欠债,维护rec表示该段收入还完该段可以还(因为先后顺序导致的)的债以后,还可以还多少钱,然后就有

sum[i]=sum[ls]+min(0, sum[rs]+rec[ls]);

rec[i]=max(rec[ls]+rec[rs]+sum[rs],rec[rs]);

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
#define mxp 610000
int ll[mxp<<2],rr[mxp<<2];
long long sum[mxp<<2],rec[mxp<<2];
const int maxx=365*24*60-1;
int day[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int n;
void init(){
	int sum=0;
	for(int i=0;i<=12;++i){
		sum+=day[i];
		day[i]=sum;
	}
}
void build(int l,int r,int id){
	ll[id]=l;
	rr[id]=r;
	sum[id]=rec[id]=0LL;
	if(l==r)	return;
	int m=(l+r)>>1,ls=id<<1,rs=ls|1;
	build(l,m,ls);
	build(m+1,r,rs);
}
int convert(char a[],char b[]){
	int tem=(a[3]-'0')*10+(a[4]-'0');
	int t=(a[0]-'0')*10+(a[1]-'0');
	tem=((day[tem-1]+t-1)*24+(b[0]-'0')*10+(b[1]-'0'))*60+((b[3]-'0')*10+(b[4]-'0'));
	return tem;
}
void update(int loc,long long tgt,int id){
	if(ll[id]==rr[id]){
		sum[id]=tgt;
		if(tgt>0){
			sum[id]=0LL;
			rec[id]=tgt;
		}
		return;
	}
	int m=(ll[id]+rr[id])>>1,ls=id<<1,rs=ls|1;
	if(loc<=m)	update(loc,tgt,ls);
	else	update(loc,tgt,rs);
	sum[id]=sum[ls]+min(rec[ls]+sum[rs],0LL);
	rec[id]=max(rec[ls]+sum[rs]+rec[rs],rec[rs]);
}
int main(){
	while(scanf("%d",&n)!=EOF){
		init();
		build(0,maxx,1);
		long long tem;
		char a[10],b[10];
		for(int i=0;i<n;++i){
			scanf("%I64d%s%s",&tem,a,b);
			int loc=convert(a,b);
			update(loc,tem,1);
			printf("%I64d\n",sum[1]);
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值