https://vjudge.net/problem/HDU-6756
题目大意:给你一个无向图,每个点有权值a,将f(u)定义为对u的邻居的集合求mex;
有两个操作:
1:将u的权值修改为x
2:查询f(u)
数据量在1e5,可以考虑分块,我们按照每个点的度数将点分为大小点,小于sqrt(n)的为小点,否则为大点。
先预处理分块。
修改操作:
如果为小点,则直接修改他的所有邻居
如果为大点,我们就先不修改他的邻居,我们使用一个容器来记录大点的邻居(大点不会很多的)的当前贡献,等到在查询的时候,我们会先遍历一遍大点的邻居,如果邻居当前的贡献不等于邻居现在的权值的话,说明该大点邻居已经被修改过了,那么我们直接修改该邻居的贡献。
查询操作:直接分块查询mex,先查询每个快是不是满了,不满的话说明答案就在这个块中。
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <cstdlib>
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define FILL(a,b) (memset(a,b,sizeof(a)))
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(a) ((a)&-(a))
#define ios std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
#define fi first
#define sc second
#define scd(a) scanf("%d",&a)
#define scdd(a,b) scanf("%d%d",&a,&b)
#define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define ac cout<<ans<<"\n"
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pii;
int dx[4]= {-1,1,0,0},dy[4]= {0,0,1,-1};
const ll mod=1e9+7;
const ll N =1e5+10;
const ll M =250000;
const double eps = 1e-4;
//const double pi=acos(-1);
ll qk(ll a,ll b){ll ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b/=2;}return ans%mod;}
int a[N],block_size=0;
vector<int> g[N];
vector<int>tag[N],cnt[N];
vector<pii>big_n[N];
int n,m;
int du[N];
void _insert(int u,int sum){if(sum>du[u]) sum=du[u]+1;//答案不会超过他的度数cnt[u][sum]++;if(cnt[u][sum]==1) tag[u][sum/block_size]++;
}
void _del(int u,int sum){if(sum>du[u]) sum=du[u]+1;cnt[u][sum]--;if(cnt[u][sum]==0) tag[u][sum/block_size]--;
}
void build(){for(int i=1;i<=n;i++){cnt[i].resize(du[i]+2);//每个点块内的大小tag[i].resize(du[i]/block_size+2);//每个点快的数量for(int v:g[i]){if(du[v]>block_size){big_n[i].push_back({v,a[v]});//记录大点邻居}_insert(i,a[v]);}}
}
int q1(int u){for(int i=0;i<=du[u]/block_size;i++){//分块查询int k=tag[u][i];if(k==block_size) continue;for(int j=i*block_size;j<i*block_size+block_size;j++){if(!cnt[u][j]) return j;}}
}
void sovle(){scanf("%d%d",&n,&m);block_size=sqrt(n);for(int i=1;i<=n;i++) scd(a[i]);for(int i=1;i<=m;i++){int u,v;scdd(u,v);g[u].push_back(v);g[v].push_back(u);du[u]++;du[v]++;}build();int q;scd(q);//cout<<1<<endl;while(q--){int x, u;scanf("%d%d",&x,&u);if(x==1){int k;scanf("%d",&k);if(du[u]<=block_size){//小点直接修改for(int v:g[u]){_del(v,a[u]);_insert(v,k);}}a[u]=k;}else {for(pii &v:big_n[u]){//先查询大点邻居的值是否改变。if(a[v.fi]!=v.se){_del(u,v.se);_insert(u,a[v.fi]);v.se=a[v.fi];}}printf("%d\n",q1(u));}}for(int i=1;i<=n;i++) g[i].clear(),big_n[i].clear(),tag[i].clear(),cnt[i].clear(),du[i]=0;
}
int main()
{
#ifdef LOCALfreopen("in.txt", "r", stdin);
#else//iosint t=1;cin>>t;while(t--) sovle();
#endif // LOCALreturn 0;
}