2020杭电多校赛第一场1006 Finding a MEX(hdu6756)

1006 Finding a MEX(hdu6756)

题意:有一个无向图,n个点m条边(n,m≤1e5),每个点都有一个点权 A u A_u Au( A u A_u Au≤1e9),有两种操作(操作数≤1e5):
操作1为 1 u x,是直接把u点的点权改成x。
操作2为 2 u,是询问u所有出边连向的点的点权中没出现的最小的非负整数是多少。

解法:首先,可以保证对于每个顶点,操作2的答案最大就是它的度。而最多有1e5条边,那么度数大于等于350的点最多只有350个,运用到这个性质,那么可以把点分为两部分,度数大于350的以及度数小于350的。对于度小于350的那部分,直接暴力求是 O ( n n ) O(n\sqrt n ) O(nn ),而对于大于350的那部分,要求最小的未出现的非负整数可以选择二分+树状数组,统计权值出现的次数,二分答案,用树状数组检测答案是否正确,要特判一下0嗷,树状数组上插入0会死循环。

代码

#include<cstdio>
#include<vector>
#include<cmath>
#include<cstring>
using namespace std;
const int N = 2e5+10;
int n, m, u, v, q, opt, x;
int val[N], a[455], isbig[N];
vector<int> tu[N], tr[N], btu[N], num[N];
//树状数组
int lowbit(int x) {
    
     return x & -x; }
void upd(int x, int p, int d) {
    
    
	for( ; p <= tu[x].size(); p += lowbit(p)) tr[x][p] += d;
}
int que(int x, int p) {
    
    
	int ans = 0;
	for( ; p > 0; p -= lowbit(p)) ans += tr[x][p];
	return ans;
}
int main() {
    
    
	int T; scanf("%d", &T);
	while(T--) {
    
    
		
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= n; ++i) {
    
    
			scanf("%d", &val[i]);
			isbig[i] = 0;
			tu[i].clear(); btu[i].clear(); num[i].clear(); tr[i].clear();
		}
		
		for(int i = 0; i < m; ++i) {
    
    
			scanf("%d%d", &u, &v);
			tu[u].push_back(v); 
			tu[v].push_back(u);
		}
		
		int sq = 450, len;
		for(int i = 1; i <= n; ++i) {
    
    
			if(tu[i].size() >= sq) {
    
    
				len = tu[i].size(); isbig[i] = 1;
				tr[i].resize(len+2, 0);
				num[i].resize(len+2, 0);
				for(int j = 0; j <= len; j++) tr[i][j] = num[i][j] = 0;
				for(int j = 0, mid; j < len; ++j) {
    
     
					mid = val[tu[i][j]]; btu[tu[i][j]].push_back(i);
					if(mid > len) continue;
					++num[i][mid];
					if(mid && num[i][mid] == 1) upd(i, mid, 1);
				}
			}
		}
		scanf("%d", &q);
		while(q--) {
    
    
			scanf("%d%d", &opt, &u);
			if(opt == 1) {
    
     
				scanf("%d", &x);
				if(val[u] == x) continue;
				len = btu[u].size();
				for(int i = 0, v; i < len; ++i) {
    
     		
					v = btu[u][i];  
					if(val[u] <= tu[v].size()) {
    
     
						--num[v][val[u]]; 
						if(val[u] && !num[v][val[u]]) upd(v, val[u], -1);
					} 
					if(x <= tu[v].size()) {
    
     
						++num[v][x];
						if(x && num[v][x] == 1) upd(v, x, 1);
					}  
				} 
				val[u] = x;
			} else {
    
     
				if(isbig[u]) {
    
     
					if(!num[u][0]) {
    
     
						puts("0"); continue;
					} 
					int l = 1, r = tu[u].size(), mid, ans = 0;
					while(l <= r) {
    
     
						mid = l + r >> 1;
						if(que(u, mid-1) == mid-1) ans = mid, l = mid + 1;
						else r = mid - 1;
					}
					printf("%d\n", ans);
				} else {
    
    
					len = tu[u].size();
					for(int i = 0; i <= len; i++) a[i] = 0;
					for(int i = 0, mid; i < len; ++i) {
    
    
						mid = val[tu[u][i]];
						if(mid <= len) ++a[mid];
					}
					for(int i = 0; i <= len; ++i) 
						if(!a[i]) {
    
     printf("%d\n", i); break; }
				}
			}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43408978/article/details/109059530