题目大意:给出一个 n 个点和 m 条边的无向图,每个点都有一个权值,现在需要执行 q 次操作,每次操作分为两种类型:
1 pos val :将第 pos 个点的权值修改为 val
2 pos :询问第 pos 个点相邻的所有点的权值组成的集合的 mex
题目分析:只能说数据水了,如果数据拉满 std 的复杂度应该是会 TLE 的
很显然的几个结论是:
设点 u 的度数为 du[ u ] ,则 mex( u ) 的答案一定小于等于 du[ u ]
度数大于等于 sqrt( n ) 的点的个数一定小于等于 sqrt( n ) 个
这样一来考虑 sqrt 分块,对于每个度数大于 sqrt( n ) 的结点维护一个树状数组,树状数组记录一下相邻的结点的权值都出现了哪些,这样就可以二分去统计出 mex 了
综上所述,对于操作 1 ,只需要更新 pos 结点周围所有度数大于 sqrt( n ) 的结点的树状数组就好了,因为最多只有 sqrt( n ) 个结点,最坏情况就是这个 pos 结点连接了 sqrt( n ) 个结点,对于每个节点的更新,只需要对树状数组进行单点更新,所以最坏的时间复杂度为 sqrt( n ) * log n
对于操作 2 ,如果 pos 节点的度数小于 sqrt( n ) 的话,直接暴力查询就好了,时间复杂度为 sqrt( n ) ,如果度数大于等于 sqrt( n ) 的话,就以 logn * logn 的时间复杂度在树状数组上二分就可以查询答案了
总的时间复杂度为 T * n * sqrt( n ) * logn
注意,因为对于这个思路来说,只需要对于度数大于等于 sqrt( n ) 建立一个更新 + 查询都是 log 级别的数据结构即可,也不难想到用 set 维护 0 ~ du[ i ] 内没有出现的数字,亦或者直接在线段树上二分,不过前者好像是常数太大,无论如何优化仍然 TLE,后者是因为区间大小问题不方便操作(或许可以用线段树AC,不过个人感觉树状数组来写这个题目更为简单)