更新一下这题的n*sqet(n)解法。
我们发现:这题要么更新是O(n),查询是O(1),要么更新是O(1),查询是O(n).
我们可以采取均摊复杂度的思想,让查询和更新都做到O(sqrt(n)).
每次更新:若当前节点的度数小于等于根号n,那么则暴力更新其周围节点。否则不管,其影响留到查询时更新。
查询时:点x的周围节点,度数小于等于根号n的节点更新对x造成的影响已经更新。只需要考虑度数大于根号n的节点更新对x造成的影响。由于x周围度数大于根号n节点不会超过根号n个,所以此次更新影响也是根号n级别的。等查询完mex后,消除影响。
这样可以不用维护影响的变化。然后这样更新和查询都是根号n次。
我们用分块维护mex。把vs数组进行分块,显然mex表示从前往后,第一个不满的块中第一个vs为0的数。
所以我们只需要维护每个块是否为满即可。所以每次更新只需要让点val所在块的度数加减1即可,这里是O1更新的。
而最后查询时根号n即可。注意这里的查询根号n与更新根号n是独立的,即复杂度分开。
所以总复杂度为:O(n*sqrt(n)) !;
注意:vector重新定义空间最好用assign(n,a),开辟n个元素,并且都赋值为a,而resize赋值不会赋值已经存在的元素。因为这卡半天。。
#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 int M = 1e5+7;
vector<int>v[M],g[M];
struct Block {
vector<int>nm,vs,bel;
vector<pair<int,int> >rg;
int bs,sz,V;
void build(int u)
{
V=g[u].size()+1;sz=sqrt(V+0.5);
rg.clear();bs=0;vs.clear();
nm.assign(V+1,0);bel.assign(V+1,0);
for(int i=0;i<=V;i+=sz)
{
rg.emplace_back(i,min(i+sz-1,V));
for(int j=i;j<=min(i+sz-1,V);j++)bel[j]=bs;
++bs;
vs.pb(0);
}
}
void ins(int x)
{
if(x>V)return ;//mex不可能比V还大(因为最多V个数,mex最大为 V+1,有用数的最大为 V)
nm[x]++;
if(nm[x]==1)vs[bel[x]]++;
}
void del(int x)
{
if(x>V)return ;
nm[x]--;
if(nm[x]==0)vs[bel[x]]--;
}
int qu()
{
for(int i=0;i<bs;i++)
{
if(vs[i]==rg[i].second-rg[i].first+1)continue;//这一块满了,最小不存在整数不在这一块
for(int j=rg[i].first;j<=rg[i].second;j++)
if(!nm[j])return j;
}
return V+1;
}
} p[M];
//struct BLOCK{
//}p[M];
int a[M];
int main()
{
int T;
cin>>T;
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
int SZ=sqrt(n+0.5);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),g[i].clear(),v[i].clear();
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
g[x].pb(y),g[y].pb(x);
}
for(int x=1;x<=n;x++)
{
p[x].build(x);
// cout<<"ojk1"<<endl;
for(auto y:g[x])
{
if(g[y].size()>SZ)v[x].pb(y);
else p[x].ins(a[y]);
}
}
int q;
scanf("%d",&q);
while(q--)
{
int ty,x,y;
scanf("%d",&ty);
if(ty==1)
{
scanf("%d%d",&x,&y);
if(g[x].size()<=SZ)
{
for(auto t:g[x])
{
p[t].del(a[x]);
p[t].ins(y);
}
}
a[x]=y;
}
else
{
scanf("%d",&x);
for(auto t:v[x])
p[x].ins(a[t]);//点x周围,size>SZ的点还未更新周围
printf("%d\n",p[x].qu());
for(auto t:v[x])
p[x].del(a[t]);
}
}
}
return 0;
}