题意
美团点评上有很多餐馆优惠券,用户可以在美团点评App上购买。每张优惠券有一个唯一的正整数编号。当用户在相应餐馆就餐时,可以在餐馆使用优惠券进行消费。优惠券的购买和使用按照时间顺序逐行记录在日志文件中,运营人员会定期抽查日志文件看业务是否正确。业务正确的定义为:一个优惠券必须先被购买,然后才能被使用。
某次抽查时,发现有硬盘故障,历史日志中有部分行损坏,这些行的存在是已知的,但是行的内容读不出来。假设损坏的行可以是任意的优惠券的购买或者使用。
现在问这次抽查中业务是否正确。若有错,输出最早出现错误的那一行,即求出最大s,使得记录1到s-1满足要求;若没有错误,输出-1。
思路
对于每一次在有该优惠券的时候买入或者在没有该优惠券的时候卖使用都需要用一个?先进行一次使用或买入操作,而且只能动最后一次出现对这个优惠券操作之后的?才能保证不破坏之前的买入使用操作,用树状数组维护比某个数大的第一个数是多少,然后进行操作即可,如果出现需要?但没有符合条件的?的话那么就截止到这里了,如果到最后都没问题那记录就是正确的
代码
#include <cstdio>
#include <set>
#include <algorithm>
using namespace std;
int status[100001],num[500001],e[100001];
char type[500001];
int BIT[500001];
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int d)
{
while(x<=500000)
{
BIT[x]+=d;
x+=lowbit(x);
}
}
int sum(int x)
{
int ret=0;
while(x>0)
{
ret+=BIT[x];
x-=lowbit(x);
}
return ret;
}
int find_kth(int k)
{
int ans=0,cnt=0;
for(int i=19;i>=0;i--)
{
ans+=(1<<i);
if(ans>500000||cnt+BIT[ans]>=k)
ans-=(1<<i);
else cnt+=BIT[ans];
}
return ans+1;
}
int main()
{
int m,ans,cnt;
int p;
while(scanf("%d",&m)!=EOF)
{
for(int i=1;i<=m;i++)
{
scanf(" %c",&type[i]);
if(type[i]!='?')
scanf("%d",&num[i]);
}
ans=-1;
cnt=0;
for(int i=1;i<=m;i++)
if(type[i]=='I')
{
if(status[num[i]]==0)
{
status[num[i]]=1;
e[num[i]]=i;
}
else
{
p=find_kth(sum(e[num[i]])+1);
if(p==500001)
{
ans=i;
break;
}
else
{
update(p,-1);
e[num[i]]=i;
}
}
}
else if(type[i]=='O')
{
if(status[num[i]]==1)
{
status[num[i]]=0;
e[num[i]]=i;
}
else
{
p=find_kth(sum(e[num[i]])+1);
if(p==500001)
{
ans=i;
break;
}
else
{
update(p,-1);
e[num[i]]=i;
}
}
}
else update(i,1);
printf("%d\n",ans);
for(int i=1;i<=100000;i++)
status[i]=0;
for(int i=1;i<=100000;i++)
e[i]=0;
for(int i=1;i<=500000;i++)
BIT[i]=0;
}
return 0;
}