https://nanti.jisuanke.com/t/42547
学习自https://www.cnblogs.com/zxytxdy/p/12375629.html
顺便复习了一下树状数组套主席树怎么写,上一次写好像是17年= =
要维护区间有哪些值,所以主席树搞搞,然后又因为要变化,显然就是套个树状数组在外面
然后这题关键是怎么求出区间所有值可组成的总和的mex
首先1不行的话,然后是2,然后由于12都行了,所以然后是3,再然后就是5,也就是说我们只要判断fibonacci数列上的数是否存在就行了,由于ai最大是2e5,所以暴力查询的次数并不会很多
复杂度是nlog^3 ,15s常数再大也够了,我的只在计蒜客上跑了1s多点
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=2e5+10;
const int len=2e5;
int n,m,tot,cnt1,cnt2;
int a[maxl],rt[maxl*80],rt1[maxl*80],rt2[maxl*80];
struct node
{
ll sum;
int ls,rs;
}tr[maxl*80];
inline void upd(int &o,int l,int r,int x,int val)
{
if(!o) o=++tot;
if(l==r)
{
tr[o].sum+=val;
return;
}
int mid=(l+r)>>1;
if(x<=mid)
upd(tr[o].ls,l,mid,x,val);
else
upd(tr[o].rs,mid+1,r,x,val);
tr[o].sum=tr[tr[o].ls].sum+tr[tr[o].rs].sum;
}
inline void updbit(int i,int x,int val)
{
while(i<=n)
upd(rt[i],1,len,x,val),i+=i&-i;
}
inline void prework()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
updbit(i,a[i],a[i]);
}
inline void prert(int l,int r)
{
cnt1=cnt2=0;
for(int i=l-1;i;i-=i&-i)
rt1[++cnt1]=rt[i];
for(int i=r;i;i-=i&-i)
rt2[++cnt2]=rt[i];
}
inline ll ask(int l,int r,int k)
{
ll ans=0;
if(r==k)
{
for(int i=1;i<=cnt1;i++)
ans-=tr[rt1[i]].sum;
for(int i=1;i<=cnt2;i++)
ans+=tr[rt2[i]].sum;
return ans;
}
int mid=(l+r)>>1;
if(k<=mid)
{
for(int i=1;i<=cnt1;i++)
rt1[i]=tr[rt1[i]].ls;
for(int i=1;i<=cnt2;i++)
rt2[i]=tr[rt2[i]].ls;
return ask(l,mid,k);
}
else
{
for(int i=1;i<=cnt1;i++)
ans-=tr[tr[rt1[i]].ls].sum;
for(int i=1;i<=cnt2;i++)
ans+=tr[tr[rt2[i]].ls].sum;
for(int i=1;i<=cnt1;i++)
rt1[i]=tr[rt1[i]].rs;
for(int i=1;i<=cnt2;i++)
rt2[i]=tr[rt2[i]].rs;
return ans+ask(mid+1,r,k);
}
}
inline void mainwork()
{
for(int i=1;i<=m;i++)
{
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op==1)
{
updbit(x,a[x],-a[x]);
a[x]=y;
updbit(x,y,y);
}
else
{
ll now=1,s=0;
while(1)
{
prert(x,y);
ll t=min(now,1ll*len);
ll tmp=ask(1,len,t);
if(tmp==s)
{
printf("%lld\n",now);
break;
}
s=tmp,now=s+1;
}
}
}
}
int main()
{
prework();
mainwork();
return 0;
}