您的位置:首页 > 其它

[SCOI 2015集训-2015.4.16]Problem A(离散化+线段树)

2015-04-16 20:10 274 查看

题目描述

在如今的网络中,TCP 是一种被广泛使用的网络协议,它在传输层提供了可靠的通信服务。

众所周知,网络是存在时延的,例如用户先后向服务器发送了两个指令 op1op1 和 op2op2,并且希

望服务器先处理指令 op1op1,再处理指令 op2op2;但由于网络时延,这两个指令可能会失序到达,

而导致服务器先执行了指令 op2op2,这是我们不希望看到的。TCP 协议拥有将失序到达的报文

按顺序重组的功能,一种方法是给每一个报文打上一个时间戳。而你今天要实现的功能比这

个要简单很多。我们需要你维护一个服务器,这个服务器的功能是一个简单的栈,你会接收

三种用户的指令:

pushpush xx tt — 表示将 xx 元素入栈,这条指令的时间戳为 tt

poppop tt — 表示将栈顶元素弹出,这条指令的时间戳为 tt

peakpeak tt — 用户询问现在栈顶元素的值,这条指令的时间戳为 tt

当一条时间戳为 tt 的指令到达时,你需要进行如下处理:

1.将所有之前执行的时间戳大于 tt 的 pushpush和 poppop指令全部撤销

2.执行当前这条指令

3.按时间戳顺序重新执行在第 11 步被撤销的指令

注意你不需要撤销以及重新执行之前已经执行过的 peakpeak 指令,也就是说每一条 peakpeak指令只

有在它到达的时候会被执行一次。

我们保证每一条指令的时间戳都是唯一的;若你在需要执行一条 poppop 指令时发现当前栈为

空,则当前你可以忽略这条指令。

输入

第一行包含一个整数 nn,表示指令总数。

接下来 nn 行按指令到达服务器的顺序给出每一条指令,有三种类型

pushpush xx tt

poppop tt

peakpeak tt

输出

对于每一条 peakpeak指令,输出对应的答案占一行;若栈为空,输出−1-1。

样例输入:

7

push 100 3

push 200 7

peak 4

push 50 2

pop 5

peak 6

peak 8

样例输出

100

50

200

数据范围

对于 10%的数据,1 <= nn <= 1000;

对于 40%的数据,1 <= nn <= 80000;

对于 100%的数据,1 <= nn <= 300000,0 <= x,tx,t <= 1000000000。

思路

虽然题目非常绕口,但是可以归纳为:在查询时间tt的栈顶元素时,从头开始离线对所有时刻小于等于tt的所有操作全部进行一遍。

那么我们可以先对所有的tt离散化以减少空间消耗,然后维护一个线段树,线段树上的序列下标对应的就是时间点,线段树上某个位置tt的值为1,表示此刻有个元素入栈,并标记这个时刻入栈的是什么元素,-1表示此刻进行了一次出栈操作。因为题目要求,因此对于i>ji>j的两个操作i,ji,j,若它们都是在同一时刻,那么用新的ii覆盖序列中旧的jj。如果维护一个值xx代表当前时刻tt栈中元素个数的话,初始xx为0,从1到tt对-1 0 1序列扫一遍,若某时x=0x=0则不能做-1,否则加上序列的当前位置的元素。这样就能得到xx,而且也能想到,时刻tt时栈顶的元素是最大的i<ti,使得-1 0 1的序列上的区间[i,t][i,t]中区间和>0>0。

容易想到在线段树上维护区间和标记sum[]sum[],一个比较好做的做法就是二分ii,每次对区间求和然后修改上下界,这样的做法是O(qlog2n)O(qlog^2n)的,由于此题很坑比地卡loglog,因此是不能用这种做法的。

然后考虑更快的做法:维护线段树上的区间内最大后缀和标记maxrightmaxright,将[1,t][1,t]这段区间,拆分成尽量少的线段树结点,然后从最右边那个结点开始暴力扫,维护当前扫过的结点对应区间和sumsum,若扫到结点jj,且maxright[j]+sum>0maxright[j]+sum>0,则说明我们要找的ii就在结点jj对应的区间中,再次在这个结点对应于线段树的子树中二分查找即可。

评测结果



代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 310000
#define lson (o<<1)
#define rson (o<<1|1)
#define INF 0x3f3f3f3f

using namespace std;

//num[i]=第i次操作入栈的元素(假如第i次操作是入栈的话),val[i]=时刻i入栈的元素(假如时刻i存在入栈操作)
int cmd[MAXN],t[MAXN],num[MAXN],data[MAXN],val[MAXN]; //t[i]=离散化后第i次操作的时间
int sum_tag[MAXN<<2],maxright_tag[MAXN<<2]; //sum_tag[o]=节点o对应区间和,maxright_tag[o]=节点o中最大的后缀和

void pushup(int o)
{
sum_tag[o]=sum_tag[lson]+sum_tag[rson];
maxright_tag[o]=max(maxright_tag[lson]+sum_tag[rson],maxright_tag[rson]);
}

void update(int o,int L,int R,int pos,int val)
{
if(L==R)
{
sum_tag[o]=maxright_tag[o]=val;
return;
}
int M=(L+R)>>1;
if(pos<=M) update(lson,L,M,pos,val);
else update(rson,M+1,R,pos,val);
pushup(o);
}

int cnt=0;

struct Interval
{
int L,R,id;
Interval(){}
Interval(int _L,int _R,int _id):L(_L),R(_R),id(_id){}
}intervals[MAXN];

void getseg(int o,int L,int R,int ql,int qr)
{
if(ql==L&&qr==R)
{
intervals[++cnt]=Interval(L,R,o);
return;
}
int M=(L+R)>>1;
if(qr<=M) getseg(lson,L,M,ql,qr);
else if(ql>M) getseg(rson,M+1,R,ql,qr);
else
{
getseg(lson,L,M,ql,M);
getseg(rson,M+1,R,M+1,qr);
}
}

int BinarySearch(int o,int L,int R,int sum) //在[L,R]的节点o中找最靠右边的i,使得后缀[i,tot]中的元素和>0,(R,tot]这段区间内的元素和已知为sum
{
while(L!=R)
{
int M=(L+R)>>1;
if(sum+maxright_tag[rson]>0) o=rson,L=M+1;
else
{
sum+=sum_tag[rson];
o=lson;
R=M;
}
}
return L;
}

int main()
{
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
char s[10];
int q,n=0,tot=0;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
scanf("%s",s);
if(s[1]=='u') //1:push
{
cmd[i]=1;
scanf("%d%d",&num[i],&t[i]);
}
else if(s[1]=='o') //2:pop
{
cmd[i]=2;
scanf("%d",&t[i]);
}
else //3:peak
{
cmd[i]=3;
scanf("%d",&t[i]);
}
data[tot++]=t[i];
}
sort(data,data+tot); //时间离散化
for(int i=1;i<=q;i++) t[i]=1+lower_bound(data,data+tot,t[i])-data;
for(int i=1;i<=q;i++)
{
if(cmd[i]==1) //1:push
{
update(1,1,tot,t[i],1);
val[t[i]]=num[i];
}
else if(cmd[i]==2) //2:pop
update(1,1,tot,t[i],-1);
else
{
cnt=0;
bool flag=false;
getseg(1,1,tot,1,t[i]);
int sum=0; //sum=当前的后缀和
for(int j=cnt;j>=1;j--)
{
if(sum+maxright_tag[intervals[j].id]>0)
{
printf("%d\n",val[BinarySearch(intervals[j].id,intervals[j].L,intervals[j].R,sum)]);
flag=true;
break;
}
sum+=sum_tag[intervals[j].id]; //!!!!!
}
if(!flag) printf("-1\n");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: