【TCP网络协议问题】

题目描述

在如今的网络中,TCP 是一种被广泛使用的网络协议,它在传输层提供了可靠的通信服务。众所周知,网络是存在时延的,例如用户先后向服务器发送了两个指令 op1 和 op2,并且希望服务器先处理指令 op1,再处理指令 op2;但由于网络时延,这两个指令可能会失序到达,而导致服务器先执行了指令 op2,这是我们不希望看到的。TCP 协议拥有将失序到达的报文按顺序重组的功能,一种方法是给每一个报文打上一个时间戳。而你今天要实现的功能比这个要简单很多。我们需要你维护一个服务器,这个服务器的功能是一个简单的栈,你会接收三种用户的指令:
push x t — 表示将 x元素入栈,这条指令的时间戳为 t
pop t — 表示将栈顶元素弹出,这条指令的时间戳为 t
peak t — 用户询问现在栈顶元素的值,这条指令的时间戳为 t
当一条时间戳为 t 的指令到达时,你需要进行如下处理:
1.将所有之前执行的时间戳大于 t 的 push和 pop指令全部撤销
2.执行当前这条指令
3.按时间戳顺序重新执行在第 1 步被撤销的指令
注意你不需要撤销以及重新执行之前已经执行过的 peak 指令,也就是说每一条 peak指令只有在它到达的时候会被执行一次。
我们保证每一条指令的时间戳都是唯一的;若你在需要执行一条 pop 指令时发现当前栈为空,则当前你可以忽略这条指令。

输入

第一行包含一个整数 n,表示指令总数。接下来 n 行按指令到达服务器的顺序给出每一条指令,有三种类型
push x t
pop t
peak t

输出

对于每一条 peak指令,输出对应的答案占一行;若栈为空,输出−1。样例输入:
7
push 100 3
push 200 7
peak 4
push 50 2
pop 5
peak 6
peak 8

样例输出       
100                                                             
50                                          
200                     
对于 100%的数据,1 <= n <= 300000,0 <= x,t <= 1000000000。
 
 
 
·突出题目重点难点:

①任务按照时间顺序执行,且输入的顺序不等于时间顺序

②上面条件的基础上,当前的PEAK命令只对在这之前的命令生效(不论时间先后,意思是后面输入的任务不会产生或被造成影响)

③必须模拟每一个出栈入栈的操作,否则无法得到每一时间点的栈顶状态

④n<=300000(logn<=18.2),猜测算法时间复杂度T的范围:

(O(n)的算法不太可能)     n*logn<=T<n*logn*logn

 

·解决方案:

基本思路可以想到是线段树,构造线段树的目的是维护每一个时刻栈的出栈进栈情况:如果线段树的各节点表示离散化后的时间点的化,那么里面的值就只有三种:1,0,-1。1表示进栈一个元素(不管这个元素具体是多少,这不是线段树要表示的),-1表示出栈一个元素,0表示这时刻是一个询问。那么维护线段树的区间和就可以用正负表示当前栈里有没有元素:

image

根据栈的性质,上面这幅图还有妙用:

栈是先进后出的:如果我们从x点开始,用一个指针i向右移动,就有如下结论:【区间和sun[i,x]第一次大于0时,PEAK要找的元素必定在这个区间之中】(假设这是读入的是PEAK x)

·在上图中可以看出,其实一旦sum[i,x]大于0,那么要找的数就是i这个位置push进去的数。但有一问题:线段树是无法将叶子节点一个个遍历的(而且这样做明显时间无法承受),所以我们只能用线段树区间拆分的思想进行类似的从后向前的遍历:

image

设我们的PEAK的时间是x,那么需要在1~x时间中寻找那个当前栈顶元素究竟是谁。设[1,x]为区间P,那么在线段树上拆分为a,b,c三段区间,然后从左至右遍历c,b,a当发现当前累加的区间和大于零时,则答案必在当前循环到的区间里(比如:sum(c)<0,sum(b+c)>0那么答案就在b区间中)。至于开头说的具体数值不用管,因为在b区间里你还要进行二分查找,那么最后找到的那个点(即答案),l==r那么只需要在读入的时候记录num[]就可以直接输出num[l]或者num[r]了。

·最后一个问题:a,b,c区间可能答案就在里面,但是包含了一些-1(比如说c区间长这样:{-1,-1,-1,-1,-1,-1,-1,-1,1}很明显,答案就是最后一个1,因为前面的pop即-1都无法影响它)。这些-1会让这个区间的sum变小从而导致错误。所以我们作为判断和大于零的依据不是区间和而是最大后缀和。

(注:其实后缀和做是一种改进方法,它的原版是直接在所有区间内二分找到最靠右边的sum大于0的时间点,但这样时间会爆炸)

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

狂欢的队伍已经远去,我只能看到自己的影子……————汪峰《尘土》

转载于:https://www.cnblogs.com/Paul-Guderian/p/6788889.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值