传送门
题目描述
给你一个无向图,每个点都有一个权值
a
i
a_{i}
ai,现在有两种操作
1:将点
x
x
x的权值改为
w
w
w
2:将与点
x
x
x相连的所有点的的权值构成一个集合,求这个集合的
m
e
x
mex
mex
分析
这个题的思路比较巧妙
首先我们求
m
e
x
mex
mex有很多方法,可以直接暴力,或者树状数组二分,线段树等,但不管任何方法,要么时间复杂度不理想,要么空间复杂度不理想,那么我们就要来权衡一下
首先这个图的所有点的度数最大为
n
∗
(
n
−
1
)
n * (n - 1)
n∗(n−1),为完全图的情况下,那么这张图中点的度数大于
n
\sqrt{n}
n的点必然不会超过
n
\sqrt{n}
n个,所以我们可以考虑,对于点的度数大于
n
\sqrt{n}
n的点,可以用树状数组进行二分,对于点的度数小于
n
\sqrt{n}
n的点,可以直接暴力
时间复杂度为
O
(
n
n
)
O(n \sqrt{n})
O(nn)
代码
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
#define _CRT_SECURE_NO_WARNINGS
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef vector<int> VI;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
int gcd(int a,int b){return (b>0)?gcd(b,a%b):a;}
int a[N];
VI tr[N];
VI nums[N],G[N];
VI son[N];
bool st[N];
int sz[N];
int id[N];
int d[N];
int n,m;
int lowbit(int x){
return x & -x;
}
void add(int u,int x,int c){
for(int i = x;i <= n;i += lowbit(i)) tr[u][i] += c;
}
int sum(int u,int x){
int res = 0;
for(int i = x;i;i -= lowbit(i)) res += tr[u][i];
return res;
}
void cale(int u,int w){
for(auto v:son[u]){
int p = id[v];
if(a[u] <= d[v]){
nums[p][a[u]]--;
if(!nums[p][a[u]] && a[u]) add(p,a[u],-1);
}
if(w <= d[v]){
nums[p][w]++;
if(nums[p][w] == 1 && w) add(p,w,1);
}
}
a[u] = w;
}
int query_max(int u){
int p = id[u];
if(!nums[p][0]) return 0;
int l = 0,r = d[u];
int mex = sz[p];
while (l <= r) {
int mid = (l + r) >> 1;
if (sum(p, mid) < mid)
mex = mid, r = mid - 1;
else
l = mid + 1;
}
return mex;
}
int query_min(int u){
for(int i = 0;i <= d[u];i++) st[i] = false;
for(int v:G[u]) st[a[v]] = 1;
for(int i = 0;i <= d[u];i++) if(!st[i]) return i;
}
int main(){
int T;
read(T);
while(T--){
read(n),read(m);
int idx = 0;
for(int i = 1;i <= n;i++) {
read(a[i]),id[i] = 0;
G[i].clear();
son[i].clear();
}
while(m--){
int x,y;
read(x),read(y);
G[x].pb(y),G[y].pb(x);
d[x]++,d[y]++;
}
int limit = sqrt(n);
for(int i = 1;i <= n;i++){
if(d[i] < limit) continue;
id[i] = ++idx;
nums[idx].resize(d[i] + 5);
tr[idx].resize(d[i] + 5);
sz[idx] = d[i];
for(int j = 0;j <= d[i];j++) nums[idx][j] = tr[idx][j] = 0;
for(int j:G[i]){
if(a[j] > d[i]) continue;
nums[idx][a[j]]++;
if(nums[idx][a[j]] == 1 && a[j]) add(idx,a[j],1);
}
}
for(int i = 1;i <= n;i++)
for(int j:G[i])
if(d[j] >= limit)
son[i].pb(j);
read(m);
while(m--){
int op,x,y;
read(op),read(x);
if(op == 1){
read(y);
cale(x,y);
}
else{
if(d[x] < limit) printf("%d\n",query_min(x));
else printf("%d\n",query_max(x));
}
}
}
return 0;
}
/**
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/