[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
样例输出
10050
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; }
相关文章推荐
- [SCOI 2015集训-2015.4.16]Problem B(计算几何+极角序二分)
- [Codeforces 460E][SCOI 2015集训]Roland and Rose(暴力乱搞)
- bzoj 4448: [Scoi2015]情报传递 可持久化线段树+离线
- UOJ #164. 【清华集训2015】V | 线段树
- [历史最值线段树] UOJ#164. 【清华集训2015】V
- UOJ #164. 【清华集训2015】V 线段树
- [BZOJ] 1067 - [SCOI2007] - 降雨量 - 离散化 + 线段树 + 讨论 + 正确的对拍姿势
- [SCOI 2015集训]B
- 2015 UESTC 数据结构专题A题 秋实大哥与小朋友 线段树 区间更新,单点查询,离散化
- BZOJ4447: [Scoi2015]小凸解密码
- 【bzoj4443】[Scoi2015]小凸玩矩阵
- HDU - 3450 - Counting Sequences (线段树|树状数组 + 离散化)
- BZOJ 3995 Sdoi2015 道路修建 线段树
- poj 1436 区间线段树 离散化
- ZOJ 3299-Fall the Brick(线段树+离散化)
- 线段树 poj 2528 离散化处理
- 离散化+线段树 poj2528
- Codeforces VK Cup 2015 - Qualification Round 1 D. Closest Equals 离线线段树 求区间相同数的最小距离
- 【BZOJ】【P1858】【Scoi2010】【序列操作】【题解】【线段树】
- poj(2528)——Mayor's posters(线段树+离散化)