题目传送门
题意: 给你一个n个数的数组,有q次询问,每一询问一个数k,如果k大于等于0,则把k插入数组中,如果k小于0,则删除数组中第丨k丨大的。最后如果数组中还有数,则随便输出一个数组中的数,否则输出0。
空间特殊要求: 28M。
线段树思路: 线段树维护区间内存在的数的个数,每次插入就向下查询到l==r的时候,sum[p]++,每次删除的时候就判断第k大的数是在左儿子还是右儿子,右儿子的话要查询右儿子中第k-sum[ls]大的数。最后如果sum[1]不等于0的话,说明数组中还有数,向下查询查到非空直接返回,否则输出0。
线段树代码:
#include<bits/stdc++.h>
#define endl '\n'
#define null NULL
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define ll long long
//#define int long long
#define vi vector<int>
#define mii map<int,int>
#define pii pair<int,int>
#define ull unsigned long long
#define all(x) x.begin(),x.end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read(){int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
return x*f;}
using namespace std;
const int N=1e6+5;
const int inf=0x7fffffff;
const int mod=998244353;
const double eps=1e-6;
const double PI=acos(-1);
int sum[N<<2];
void in(int p,int l,int r,int k)
{
if(l==r)
{
sum[p]++;
return ;
}
int mid=l+r>>1;
if(k<=mid)
in(ls,l,mid,k);
else
in(rs,mid+1,r,k);
sum[p]=sum[ls]+sum[rs];
}
void del(int p,int l,int r,int k)
{
if(l==r)
{
sum[p]--;
return ;
}
int mid=l+r>>1;
if(sum[ls]>=k)
del(ls,l,mid,k);
else
del(rs,mid+1,r,k-sum[ls]);
sum[p]=sum[ls]+sum[rs];
}
int ask(int p,int l,int r)
{
if(l==r)
{
return l;
}
int mid=l+r>>1;
if(sum[ls]!=0)
return ask(ls,l,mid);
if(sum[rs]!=0)
return ask(rs,mid+1,r);
}
signed main()
{
int n=read(),q=read();
for(int i=1;i<=n;i++)
{
int x=read();
in(1,1,n,x);
}
while(q--)
{
int x=read();
if(x>0)
in(1,1,n,x);
else
{
x=-x;
del(1,1,n,x);
}
}
if(sum[1]!=0)
{
cout<<ask(1,1,n)<<endl;
}
else
cout<<0<<endl;
}
树状数组思路: 众所周知,树状数组在某些方面可以代替线段树精简地完成一些操作,二者时间都是log级别的,但是树状数组的常数要比线段树好,空间也比线段树小。查位置的时候用到二分查询,如果前面的总个数小于k,说明第k个在右边,否则在左边,最后查询到了就对这个点进行-1操作。(ask(i)表示数组元素中在1~i内的个数)
树状数组代码
#include<bits/stdc++.h>
#define endl '\n'
#define null NULL
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define ll long long
//#define int long long
#define vi vector<int>
#define mii map<int,int>
#define pii pair<int,int>
#define ull unsigned long long
#define all(x) x.begin(),x.end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read(){int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
return x*f;}
using namespace std;
const int N=1e6+5;
const int inf=0x7fffffff;
const int mod=998244353;
const double eps=1e-6;
const double PI=acos(-1);
int c[N];
int lowbit(int x)
{
return x&-x;
}
void add(int x,int k)
{
for(int i=x;i<N;i+=lowbit(i))
c[i]+=k;
}
int ask(int x)
{
int res=0;
for(int i=x;i;i-=lowbit(i))
res+=c[i];
return res;
}
signed main()
{
int n=read(),q=read();
for(int i=1;i<=n;i++)
{
int x=read();
add(x,1);
}
while(q--)
{
int x=read();
if(x>0)
add(x,1);
else
{
x=-x;
int l=1,r=1e6;
while(l<r)
{
int mid=l+r>>1;
if(ask(mid)<x)
l=mid+1;
else
r=mid;
}
add(r,-1);
}
}
if(ask(N-1))
{
for(int i=1;i<=n;i++)
{
if(c[i])
{
cout<<i<<endl;
break;
}
}
}
else
cout<<0<<endl;
}