“科大讯飞杯”第十七届同济大学程序设计预选赛暨高校网络 H.时空栈

题目链接
思路:显然对于每个操作,只能被他之前的且时间小于他的操作所影响。
把所有的时间离散化之后,用时间为下标建立区间线段树,下标为 g g g的值为 s g s_g sg
枚举所有操作 ( o p , t , v ) (op,t,v) (op,t,v)
把入栈当成区间 [ t , n ] + 1 [t,n]+1 [t,n]+1,出栈为区间 [ t , n ] − 1 [t,n]-1 [t,n]1
因为保证所有的操作是合法的,那么查询时刻T的栈顶元素的时候,此时线段树上下标为 t t t的值为 s x s_x sx,那么必然有一个位置 y y y满足 s x − s y > 0 s_x-s_y>0 sxsy>0,那么此时的栈顶元素必然是由第一个时间点大于y的的操作产生的,模拟以上操作即可。

#include 
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
struct uzi{
    int op,t,v;
    bool operator < (const uzi & T)const{
        return t<T.t;
    }
}p[N],q[N];
int n,T[N],ans[N],f[N];
int tr[N<<2],laz[N<<2];
#define mid (l+r>>1)
#define ls o<<1
#define rs o<<1|1
void pd(int o){
    laz[ls]+=laz[o];
    laz[rs]+=laz[o];
    tr[ls]+=laz[o];
    tr[rs]+=laz[o];
    laz[o]=0;
    return ;
}
void add(int o,int l,int r,int x,int y,int d){
    if(l>=x && r<=y){
        tr[o]+=d;
        laz[o]+=d;
        return ;
    }
    pd(o);
    if(x<=mid)add(ls,l,mid,x,y,d);
    if(y>mid)add(rs,mid+1,r,x,y,d);
    tr[o]=min(tr[ls],tr[rs]);
    return ;
}
int pa(int o,int l,int r,int d){
    if(l==r && d-tr[o]>0)return l;
    if(l==r)return -1;
    pd(o);
    if(d-tr[rs]>0)return pa(rs,mid+1,r,d);
    if(d-tr[ls]>0)return pa(ls,l,mid,d);
    return -1;
}
int get(int o,int l,int r,int x,int y,int d){
    if(l>=x && r<=y){
        return pa(o,l,r,d);
    }
    if(l>y||r<x|| l>r)return -1;
    pd(o);
    int an=-1;
    if(mid<=y)an=max(an,get(rs,mid+1,r,x,y,d));
    if(x<=mid)an=max(an,get(ls,l,mid,  x,y,d));
    return an;
}
int sa[N];
void adda(int p,int d){
    for(;p<N;p+=p&-p)sa[p]+=d;
}
int geta(int p){
    int sz=0;
    for(;p;p-=p&-p)sz+=sa[p];
        return sz;
}
set<pair<int,int>>s;
int ti[N];
int main() {
  ios::sync_with_stdio(false);
  cin>>n;
  for(int i=1;i<=n;i++){
    cin>>p[i].op>>p[i].t;
    if(p[i].op==0)cin>>p[i].v;
  }
  for(int i=1;i<=n;i++)ti[i]=p[i].t;
    sort(ti+1,ti+1+n);
  int len=unique(ti+1,ti+1+n)-ti-1;
  for(int i=1;i<=n;i++)p[i].t=lower_bound(ti+1,ti+1+len,p[i].t)-ti,f[p[i].t]=i;
    int d=0;
  for(int i=1;i<=n;i++){
    if(p[i].op==0){
        add(1,0,len,p[i].t,len,1);
        s.insert({p[i].t,p[i].v});
        adda(p[i].t,1);
    }else if(p[i].op==1){
        add(1,0,len,p[i].t,len,-1);
        adda(p[i].t,-1);
    }else{
        int pos=get(1,0,len,0,p[i].t-1,geta(p[i].t));
        assert(pos!=-1);
        auto f=s.lower_bound({pos+1,0});
        assert(f!=s.end());
        cout<<(*f).se<<endl;
    }
  }
   
    return 0;
}

你可能感兴趣的:(线段树)