图染色

图染色

根号分治

图染色 - 题目 - Daimayuan Online Judge

图染色问题一般可用,树染色可用 dp 等方法

  1. 设一个阈值 M
  2. 度数大于 M 的点可设为大点,<= M 的设为小点

查询

  1. 若为小点,直接暴力枚举邻居,最多枚举 M 个
  2. 若为大点,不能暴力枚举,可考虑在修改的时候就算出来大点的答案

修改

​ 可预处理出每个点的大点邻居,存到 B 数组里,当反转这个点时,直接更新它的大点邻居,复杂度为 \(O(\frac {边数}M)\)

​ 不能也更新小点,因为小点邻居可能很多

设 M 为 \(\sqrt {边数}\) 即可

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;
#define endl "\n"

typedef long long ll;
typedef pair<int, int> PII;

const int N = 2e5 + 10, M = 500;
int n, m, q;
vector<vector<int> > G(N), B(N);
bool big[N];
int col[N], ans[N];
void add(int u, int v)
{
	G[u].push_back(v);
}
int main()
{
	scanf("%d%d%d", &n, &m, &q);
	while(m--)
	{
		int u, v;
		scanf("%d%d", &u, &v);
		add(u, v), add(v, u);
	}
	for (int i = 1; i <= n; i++)
		if (G[i].size() > M) big[i] = true;

	for (int u = 1; u <= n; u++)
	{
		for (auto v : G[u])
		{
			if (big[v])
				B[u].push_back(v);
		}
	}
	while(q--)
	{
		int op, x;
		scanf("%d%d", &op, &x);
		if (op == 1)
		{
			col[x] ^= 1;
			for (int y : B[x])
			{
				if (col[x])
					ans[y]++;
				else
					ans[y]--;
			}
		}
		else
		{
			if (big[x])
				printf("%d\n", ans[x]);
			else
			{
				int cnt = 0;
				for (int y : G[x])
					cnt += col[y];
				printf("%d\n", cnt);
			}
		}
	}
    return 0;
}
posted @ 2022-06-11 11:52  hzy0227  阅读(52)  评论(0编辑  收藏  举报