我主要是按题解思路写的
我们发现修改和询问两个操作都和点的度直接相关,直接修改或者询问的话复杂度无法保证(菊花图 度接近n) 那我们得想办法进行一个分类讨论
我们设置大点和小点。设置一个临界值为sqn 其值为根号n
如果一个点的度大于等于根号n 那么我们把它分为大点
否则我们把它分为小点
首先我们用树状数组维护mex(对每个点开一个树状数组) 并且 将所有的点和与它相连的大点构成另外一个大点图 (在这个图中 对于点u来说 和它相连的都是大点)
对于修改操作 如果当前点是小点 我们直接暴力更新 因为它的度小于sqn 所以单次复杂度是 sqn*logn的 如果是大点我们直接更新 单次复杂度 o(1)
对于询问操作 因为小点的信息已经到位了 假设当前询问的点为 u 我们暴力遍历u的大点图 将大点的信息 放入u的树状数组
求一次mex 完成后再撤销 因为大点的个数不超过 sqn个 所以复杂度为 sqn*logn
如此下来总的复杂度 是 q*sqn*logn
另外树状数组只要开 d[i]大小 d[i]为i点的度数 我们知道每个点i 的答案不会超过d[i] 所以对于大于d[i]的权值我们也不必要讨论
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n,m,sqn=350,d[N],val[N];
int bh[N],bnex[N<<1],bto[N<<1],bcur;
int h[N],nex[N<<1],to[N<<1],cur;
const int inf = 1e9;
vector<int>BIT[N],cnt[N];
inline int in(){
int x=0;char c=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x;
}
void badd_edge(int x,int y){
bto[++bcur]=y;bnex[bcur]=bh[x];bh[x]=bcur;
}
void add_edge(int x,int y){
to[++cur]=y;nex[cur]=h[x];h[x]=cur;
}
void init(){
for(int i = 0; i <= n; i++){
BIT[i].clear();
cnt[i].clear();
h[i]=bh[i]=d[i]=0;
}
bcur=cur=0;
}
void add(int id,int x,int val){
while(x<=d[id]){
BIT[id][x]+=val;
x+=x&-x;
}
}
int query(int id,int x){
int ret=0;
while(x){
ret+=BIT[id][x];
x-=x&-x;
}
return ret;
}
int getans(int id){
if(!cnt[id][0]) return 0;
int l=0,r=d[id],ans;
while(l<=r){
int mid = (l+r>>1);
if(query(id,mid)==mid) l=mid+1,ans=mid;
else r=mid-1;
}
return ans+1;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
n=in(),m=in();
for(int i = 1; i <= n; i++) val[i]=in();
for(int i = 1; i <= m; i++){
int u,v;
u=in();v=in();
add_edge(u,v);add_edge(v,u);
d[v]++,d[u]++;
}
for(int i = 1; i <= n; i++){
BIT[i].resize(d[i]+3);
cnt[i].resize(d[i]+3);
}
int q;
q=in();
for(int i = 1; i <= n; i++){
for(int j = h[i]; j; j = nex[j]){
int v = to[j];
if(d[v]>=sqn){
badd_edge(i,v);
}
if(d[i]<sqn){
if(val[i]<=d[v]){
cnt[v][val[i]]++;
if(cnt[v][val[i]]==1&&val[i])
add(v,val[i],1);
}
}
}
}
for(int i = 1; i <= q; i++){
int op,x,y;
op=in(),x=in();
if(op==2){
for(int j = bh[x]; j; j = bnex[j]){
int v = bto[j];
if(val[v]<=d[x]){
cnt[x][val[v]]++;
if(cnt[x][val[v]]==1&&val[v])
add(x,val[v],1);
}
}
printf("%d\n",getans(x));
for(int j = bh[x]; j; j = bnex[j]){
int v = bto[j];
if(val[v]<=d[x]){
cnt[x][val[v]]--;
if(cnt[x][val[v]]==0&&val[v])
add(x,val[v],-1);
}
}
}else{
y=in();
if(d[x]<sqn){
for(int j = h[x]; j; j = nex[j]){
int v = to[j];
if(val[x]<=d[v]){
cnt[v][val[x]]--;
if(cnt[v][val[x]]==0&&val[x])
add(v,val[x],-1);
}
if(y<=d[v]){
cnt[v][y]++;
if(cnt[v][y]==1&&y)
add(v,y,1);
}
}
}
val[x]=y;
}
// for(int i = 1; i <= n; i++) printf("i=%d rt[i]=%d\n",i,mi[rt[i]]);
}
init();
}
return 0;
}
/*
2
5 4
0 1 2 0 1
1 1
2 1
3 1
5 4
5
2 2
1 2 2
2 2
1 3 1
2 1
*/