【HDU4967】Handling the Past

题意

   模拟栈操作。有三种操作push,pop,peak分别代表从栈顶压入元素,删除栈顶元素,查询栈顶元素。但是,每个操作会给出一个时间戳,要求操作必须要按照时间戳来进行。但是对于每个peak必须马上给出查询结果。其中n<=50000,xi,ti<=1e9

分析

  讲真,这种题必须结合样例才能明白让干嘛。如果暴力的话,对于每个peak的时间复杂度都是O(n)。所以我们想到了线段树。

  1.因为t的值很大,所以我们要首先将t离散化(我因为离散化写丑了一开始还T了好几发)

  2.将每个push的t和x对应的记录下来

  3.对于每个操作push,我们在t的位置插入1,对于每个pop操作,我们在t的位置插入-1。对于每个peak操作,我们找到t左边的第一个t1,符合sum(t1 to t)>0,这时候和t1对应的x值就是答案。

思路是很好想的,然后就是操作3该怎么通过线段树来维护?

  我们通过线段树来维护一个区间和,和一个最大后缀和,然后对于没个peak查询,所有从1到t的线段树的结点,从右往左找,如果加上当前结点的最大后缀和大于0的话,这个答案就一定在这个节点内,否则加上这个结点的区间和继续往左找。这里可以结合代码进行理解。

  

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <map>
  7 
  8 using namespace std;
  9 const int maxn=50000+100;
 10 struct Ope{
 11     string name;
 12     int t,a;
 13 }ope[maxn];
 14 int n,kase;
 15 int V[maxn],M[maxn];
 16 int sumv[4*maxn],max_suff[4*maxn];
 17 int v,x;
 18 void maintain(int o){
 19     sumv[o]=sumv[2*o]+sumv[2*o+1];
 20     max_suff[o]=max(max_suff[2*o+1],sumv[2*o+1]+max_suff[2*o]);
 21 }
 22 void update(int o,int L,int R){
 23     if(L==R){
 24         sumv[o]+=x;
 25         max_suff[o]+=x;
 26         return ;
 27     }
 28     int M=L+(R-L)/2;
 29     if(v<=M)update(2*o,L,M);
 30     if(v>M)update(2*o+1,M+1,R);
 31     maintain(o);
 32     return;
 33 }
 34 int tot,ans;
 35 int ql,qr;
 36 void solve(int o,int L,int R){
 37     if(L==R){
 38         ans=L;
 39         return;
 40     }
 41     int M=L+(R-L)/2;
 42     if(tot+max_suff[2*o+1]>0)
 43       return solve(2*o+1,M+1,R);
 44     tot+=sumv[2*o+1];
 45     return solve(2*o,L,M);
 46 }
 47 void query(int o,int L,int R){
 48     if(ans!=-1)
 49         return;
 50     if(ql<=L&&qr>=R){
 51         if(tot+max_suff[o]>0){
 52             solve(o,L,R);
 53         }
 54         else tot+=sumv[o];
 55         return;
 56     }
 57     int M=L+(R-L)/2;
 58     if(M<qr)
 59         query(2*o+1,M+1,R);
 60     if(M>=ql)
 61         query(2*o,L,M);
 62     return;
 63 }
 64 int main(){
 65     kase=0;
 66     while(scanf("%d",&n)!=EOF&&n){
 67         printf("Case #%d:\n",++kase);
 68         for(int i=1;i<=n;i++){
 69             cin>>ope[i].name;
 70             if(ope[i].name=="push"){
 71                 scanf("%d%d",&ope[i].a,&ope[i].t);
 72             }
 73             if(ope[i].name=="pop"||ope[i].name=="peak"){
 74                 scanf("%d",&ope[i].t);
 75             }
 76             V[i]=ope[i].t;
 77         }
 78         sort(V+1,V+1+n);
 79         for(int i=1;i<=n;i++){
 80             if(ope[i].name=="push"){
 81                 int tt=lower_bound(V+1,V+1+n,ope[i].t)-V;
 82                 M[tt]=ope[i].a;
 83             }
 84         }
 85        /* for(int i=1;i<=n;i++){
 86             int tt=lower_bound(V+1,V+1+n,ope[i].t)-V;
 87             cout<<tt<<endl;
 88         }*/
 89 
 90         memset(sumv,0,sizeof(sumv));
 91         memset(max_suff,0,sizeof(max_suff));
 92 
 93         for(int i=1;i<=n;i++){
 94             if(ope[i].name=="push"){
 95                 v=lower_bound(V+1,V+1+n,ope[i].t)-V;
 96                 x=1;
 97                 update(1,1,n);
 98             }
 99             else if(ope[i].name=="pop"){
100                 v=lower_bound(V+1,V+1+n,ope[i].t)-V;
101                 x=-1;
102                 update(1,1,n);
103             }
104             else{
105                 ql=1,qr=lower_bound(V+1,V+1+n,ope[i].t)-V;
106                 tot=0,ans=-1;
107                 query(1,1,n);
108                 printf("%d\n",ans==-1?-1:M[ans]);
109             }
110         }
111     }
112 return 0;
113 }
View Code

 

posted @ 2018-05-08 23:16  蒟蒻LQL  阅读(217)  评论(0编辑  收藏  举报