線段樹維護區間加,區間最右邊第一個小於x的數。
先說下正解:
開一個以時間爲節點的線段樹,每個節點維護的值爲當前時間點棧內元素個數。
遇到入棧,讓t,sz 的值加1,出棧:讓t,sz的值減1.
碰到查詢操作,先查詢當前時間點的棧的元素個數nm,再查找[1,t]區間最右邊的小於nm的時間點ans。
ans+1即最後一次入棧。(可以仔細想一下爲什麼)
上述操作用線段樹處理即可。
區間加,單點查詢。
和查詢最右邊小於x的數。
我剛開始的思路是二分+線段樹,每個節點維護的是每個時間點的操作,入棧爲1,出棧爲-1.查詢時肯定是查詢區間[1,t]中
的一個區間[m,t]使得m最大,且區間和剛好大於等於1.於是用二分+區間查詢。但這是錯的!
爲什麼?因爲區間和不滿足二分性質。。
下面是AC代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 2e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
struct node{
int op,t,x;
}p[M];
int mn[M<<2],li[M],a[M],tg[M<<2];
void pu(int o,int l,int r)
{
if(!tg[o])return ;
tg[ls]+=tg[o];tg[rs]+=tg[o];
mn[ls]+=tg[o];mn[rs]+=tg[o];
tg[o]=0;
}
void up(int o,int l,int r,int x,int y,int d)
{
if(x<=l&&r<=y)
{
mn[o]+=d;
tg[o]+=d;
return ;
}
pu(o,l,r);
int m=(l+r)/2;
if(x<=m)up(ls,l,m,x,y,d);
if(y>m) up(rs,m+1,r,x,y,d);
mn[o]=min(mn[ls],mn[rs]);
}
bool f;
int tmp,ans;
int qu(int o,int l,int r,int x)//單點查詢x的值
{
if(l==r)
return mn[o];
int m=(l+r)/2;
pu(o,l,r);
if(x<=m)return qu(ls,l,m,x);
return qu(rs,m+1,r,x);
}
void qu(int o,int l,int r,int x,int y,int nm)//區間l,r 最右邊的,值小於tmp的 返回ans
{
if(r<x||l>y||f)return ;
if(l==r)
{
ans=l;
if(mn[o]<nm)f=true;
return;
}
pu(o,l,r);
int m=(l+r)/2;
if(mn[rs]<nm)qu(rs,m+1,r,x,y,nm);
qu(ls,l,m,x,y,nm);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,sz=0;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>p[i].op;
if(p[i].op==0)cin>>p[i].t>>p[i].x;
else cin>>p[i].t;
li[++sz]=p[i].t;
}
sort(li+1,li+1+sz);
for(int i=1;i<=n;i++)
{
p[i].t=lower_bound(li+1,li+1+sz,p[i].t)-li;
if(p[i].op==2)
{
int nm=qu(1,1,sz,p[i].t);//這個時刻棧中有多少元素
f=false;
qu(1,1,sz,1,p[i].t,nm);
if(!f)ans=0;
cout<<a[ans+1]<<endl;
}
else
{
if(p[i].op==0)
up(1,1,sz,p[i].t,sz,1),a[p[i].t]=p[i].x;
else up(1,1,sz,p[i].t,sz,-1);
}
}
return 0;
}
/*
8
0 6 2
2 7
0 3 3
1 5
0 1 1
2 4
2 8
2 2
*/