正题
题目链接:https://cometoj.com/contest/79/problem/E?problem_id=4207
题目大意
nnn个栈,要求支持操作
- l∼rl\sim rl∼r区间内的栈压入一个数
- l∼rl\sim rl∼r区间内的栈弹出一个数
- 求第xxx个栈内第kkk个数
解题思路
对于每个询问我们其实就是要求在他之前的第一个位置使得栈内有t−kt-kt−k个数的操作。
我们可以倒着跑,维护一个线段树表示每个询问的“倒计时”,如果是压入就对于所有询问−1-1−1,弹出就是+1+1+1,然后每次操作后0的询问答案就是该次操作。
这里可以先把没有接触到的询问都赋值为infinfinf,触碰到后再修改“倒计时”
时间复杂度O(nlogn)O(n\log n)O(nlogn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define lowbit(x) (x&-x)
using namespace std;
const ll N=2e5+10,inf=1e9;
ll n,q,l[N],r[N],v[N];
ll cnt,p[N],L[N],R[N],ans[N];
ll w[N*4],num[N*4],lazy[N*4];
void Merge(ll x){w[x]=min(w[x*2],w[x*2+1]);if(w[x*2]<w[x*2+1])num[x]=num[x*2];else num[x]=num[x*2+1];return;
}
void Downdata(ll x){if(!lazy[x])return;w[x*2]+=lazy[x];w[x*2+1]+=lazy[x];lazy[x*2]+=lazy[x];lazy[x*2+1]+=lazy[x];lazy[x]=0;return;
}
void Build(ll x,ll l,ll r){if(l==r){w[x]=inf;num[x]=l;return;}ll mid=(l+r)>>1;Build(x*2,l,mid);Build(x*2+1,mid+1,r);Merge(x);return;
}
void Updata(ll x,ll L,ll R,ll pos,ll val){if(L==R)w[x]=val;if(L>=R)return;ll mid=(L+R)>>1;Downdata(x);if(pos<=mid)Updata(x*2,L,mid,pos,val);else if(pos>mid)Updata(x*2+1,mid+1,R,pos,val);Merge(x);return;
}
void Add(ll x,ll L,ll R,ll l,ll r,ll val){if(L>R||l>r)return;if(L<1||R>cnt)return;if(l<=L&&R<=r){w[x]+=val;lazy[x]+=val;return;}ll mid=(L+R)>>1;Downdata(x);if(r<=mid)Add(x*2,L,mid,l,r,val);else if(l>mid)Add(x*2+1,mid+1,R,l,r,val);else Add(x*2,L,mid,l,r,val),Add(x*2+1,mid+1,R,l,r,val);Merge(x);return;
}
bool cmp(ll x,ll y)
{return (l[x]==l[y])?(x<y):(l[x]<l[y]);}
int main()
{scanf("%lld%lld",&n,&q);for(ll i=1;i<=q;i++){char op[10];scanf("%s",op);if(op[1]=='u'){scanf("%lld%lld%lld",&l[i],&r[i],&v[i]);}if(op[1]=='o'){scanf("%lld%lld",&l[i],&r[i]);v[i]=-inf;}if(op[1]=='i'){scanf("%lld%lld",&l[i],&r[i]);p[++cnt]=i;}}sort(p+1,p+1+cnt,cmp);for(ll i=0;i<=n+1;i++)L[i]=cnt+1;for(ll i=1;i<=cnt;i++){v[p[i]]=-i;L[l[p[i]]]=min(L[l[p[i]]],i);R[l[p[i]]]=max(R[l[p[i]]],i);}for(ll i=n-1;i>=1;i--)L[i]=min(L[i],L[i+1]);for(ll i=2;i<=n;i++)R[i]=max(R[i],R[i-1]);if(!cnt)return 0;Build(1,1,cnt);for(ll i=q;i>=1;i--){if(v[i]>=0){Add(1,1,cnt,L[l[i]],R[r[i]],-1);while(w[1]<=0){ans[p[num[1]]]=v[i];Updata(1,1,cnt,num[1],inf);}}else if(v[i]<-cnt)Add(1,1,cnt,L[l[i]],R[r[i]],1);else{Updata(1,1,cnt,-v[i],r[i]);}}for(ll i=1;i<=q;i++)if(v[i]>=-cnt&&v[i]<0)printf("%lld\n",ans[i]);return 0;
}