HDU-4967 Handling the Past (线段树)

Handling the Past

http://acm.hdu.edu.cn/showproblem.php?pid=4967

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)


Problem Description
Nowadays, cloud computing is a popular topic among business and technology circles. In cloud computing, everything can be stored in a cloud server, and clients deal with the data by sending operation-requests to the server. However, such client-server mode may cause some problems. For example, if you send two operations op1 and op2 to the server, expecting that op1 should be executed first and followed by op2. Due to the network delay, op1 may arrive at the server later than op2. In order to inform the server the correct operation order, each operation is associated with a timestamp. Now if the server gets two operations (op1, t1) and (op2, t2), where t1 < t2, the server will know that op1 should be executed earlier than op2. So, if (op2, t2) arrives first, the server will execute op2 immediately. And when (op1, t1) arrives, the server will find that op1 should be executed before op2 (because t1 < t2), thus it has to undo op2, execute op1, and re-execute op2 finally. 

In this problem, you are asked to simulate the above process. To simplify the problem, we assume that there is only a stack, a last-in-first-out data structure as you know, stored in the server. Three types of operations are considered, whose formats and semantics are given as follows.

push x t -- push x into the stack, and t is a timestamp
pop t -- pop the top element from the stack, and t is a timestamp
peak t -- return the top element in the stack, and t is a timestamp

When an operation op with a timestamp t arrives, the server process it in the following three steps:

Step 1: undo all the "push" and "pop" operations having timestamp larger than t.
Step 2: execute op.
Step 3: redo all the "push" and "pop" operations which were undone in step 1.

The server do not need to undo or redo any "peak" operations. In another word, every "peak" operation is executed only once after it arrives at the server.

Given the operations arriving at the server in order, you are asked to simulate the above process. The stack is empty initially. To simplify the problem further, another two assumptions are made:

1. All the "pop" operations are valid. In another word, if you simulate the process correctly, no "pop" operations will be performed on an empty stack.
2. All timestamps are different.
 

Input
The input contains multiple test cases.

Each case begins with an integer N (1<=N<=50000), indicating the number of operations. The following N lines each contain an operation in one of the following three formats:

push x t
pop t
peak t
where 0<=x, t<=10^9.

The operations are given in the order in which they arrive at the server.
The input is terminated by N = 0.
 

Output
For each case, output "Case #X:" in a line where X is the case number, staring from 1. Then for each "peak" operation, output the answer in a line. If the stack is empty, output -1 instead.
 

Sample Input
  
  
7 push 100 3 push 200 7 peak 4 push 50 2 pop 5 peak 6 peak 8 4 push 25 1 pop 5 peak 6 peak 3 4 push 10 1 peak 7 pop 3 peak 4 0
 

Sample Output
  
  
Case #1: 100 50 200 Case #2: -1 25 Case #3: 10 -1

初看本题完全想不到是线段树,看了题解后发现解法好巧妙

对时间按照升序排序后离散化处理,建立线区间[1,n]的线段树,线段树维护区间和与最大后缀和,push操作对相应时间+1,pop操作对相应时间-1,peak操作查询[1,t)区间内最右的tt,使[tt,t)的和大于0

注意:时间1就是操作peak时,直接输出-1

#include <cstdio>
#include <algorithm>

#define lson (i<<1)
#define rson ((i<<1)|1)

using namespace std;

int index[50005],sum,x[50005];

struct Operation {//0代表push,1代表pop,2代表peak
    int ope,x,t;
}sta[50005];

struct Node {
    int l,r,sum,rmx;
}tr[200005];

void build(int i,int l,int r) {
    tr[i].l=l;
    tr[i].r=r;
    tr[i].sum=tr[i].rmx=0;
    if(l==r)
        return ;

    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
}

void update(int i,int x,int t) {
    if(tr[i].l==tr[i].r) {
        tr[i].sum=tr[i].rmx=x;
        return ;
    }

    if(tr[lson].r>=t)
        update(lson,x,t);
    else
        update(rson,x,t);
    tr[i].sum=tr[lson].sum+tr[rson].sum;
    tr[i].rmx=max(tr[rson].rmx,tr[rson].sum+tr[lson].rmx);//当前结点的最大后缀和为 右儿子的最大后缀和 与 右儿子的区间和+左儿子的最大后缀和 的最大值
}

int query(int i,int t) {
    if(tr[i].r<=t) {
        int ss=sum+tr[i].rmx;
        if(ss<=0) {//如果最大后缀和小于等于0
            sum+=tr[i].sum;//后缀和加上本区间的和
            return -1;
        }
    }
    if(tr[i].l==tr[i].r)
        return x[tr[i].l];
    if(tr[lson].r<t) {//如果时间t不完全在左子区间
        int ans=query(rson,t);
        if(ans!=-1)//右区间找到答案
            return ans;
    }
    return query(lson,t);
}

int main() {
    int n,kase=0;
    char s[5];
    while(scanf("%d",&n),n!=0) {
        for(int i=0;i<n;++i) {
            scanf("%s",s);
            if(s[1]=='u') {
                scanf("%d%d",&sta[i].x,&sta[i].t);
                sta[i].ope=0;
            }
            else if(s[1]=='o') {
                scanf("%d",&sta[i].t);
                sta[i].ope=1;
            }
            else {
                scanf("%d",&sta[i].t);
                sta[i].ope=2;
            }
            index[i]=sta[i].t;
        }
        printf("Case #%d:\n",++kase);
        sort(index,index+n);
        for(int i=0;i<n;++i) {//离散化
            sta[i].t=lower_bound(index,index+n,sta[i].t)-index+1;//时间区间为[1,n]
            x[sta[i].t]=sta[i].x;
        }
        build(1,1,n);
        for(int i=0;i<n;++i) {
            if(sta[i].ope==0)
                update(1,1,sta[i].t);//push的时间+1
            else if(sta[i].ope==1)
                update(1,-1,sta[i].t);//pop的时间-1
            else {
                sum=0;
                printf("%d\n",sta[i].t==1?-1:query(1,sta[i].t-1));//若时间1就是peak则直接输出-1
            }
        }
    }
    return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值