BZOJ1095【动态点分治】【优先队列】

学会了用priority_queue实现带删除操作的堆.

/* I will wait for you*/

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <string>
#define make make_pair
#define fi first
#define se second

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;

const int maxn = 200010;
const int maxm = 1010;
const int maxs = 26;
const int inf = 0x3f3f3f3f;
const int P = 1000000007;
const double error = 1e-9;

inline int read()
{
	int x = 0, f = 1;
	char ch = getchar();
	while (ch <= 47 || ch >= 58)
		f = (ch == 45 ? -1 : 1), ch = getchar();
	while (ch >= 48 && ch <= 57)
		x = x * 10 + ch - 48, ch = getchar();
	return x * f;
}

struct edge
{
	int v, next;
} e[maxn];

struct heap
{
	priority_queue<int> A, B;

	void push(int c) {
		A.push(c);
	}

	void erase(int c) {
		B.push(c);
	}

	void pop() {
		while (B.size() && A.top() == B.top())
			A.pop(), B.pop();
		A.pop();
	}

	int size() {
		return A.size() - B.size();
	}

	int first() {
		while (B.size() && A.top() == B.top())
			A.pop(), B.pop();
		return A.size() ? A.top() : 0;
	}

	int second() {
		if (size() < 2)
			return 0;
		int x, y;
		x = first(), pop();
		y = first(), push(x);
		return y;
	}
} A, B[maxn >> 1], C[maxn >> 1];

int n, m, root, cnt, dfn, sum, tot, bin[maxn], lg[maxn],
    size[maxn], deep[maxn], sm[maxn], head[maxn], fa[maxn],
    st[maxn][20], pos[maxn], del[maxn], col[maxn];

void insert(int u, int v)
{
	e[cnt] = (edge) {v, head[u]}, head[u] = cnt++;
	e[cnt] = (edge) {u, head[v]}, head[v] = cnt++;
}

void dfs(int u, int p)
{
	st[++dfn][0] = deep[u], pos[u] = dfn;
	
	for (int i = head[u]; i != -1; i = e[i].next) {
		int v = e[i].v;
		if (v != p) {
			deep[v] = deep[u] + 1, dfs(v, u);
			st[++dfn][0] = deep[u];
		}
	}
}

void find(int u, int p)
{
	size[u] = 1, sm[u] = 0;
	
	for (int i = head[u]; i != -1; i = e[i].next) {
		int v = e[i].v;
		if (v != p && !del[v]) {
			find(v, u), size[u] += size[v];
			sm[u] = max(sm[u], size[v]);
		}
	}

	sm[u] = max(sm[u], sum - size[u]);

	if (sm[u] < sm[root])
		root = u;
}

void divide(int u, int p)
{
	fa[u] = p, del[u] = 1;

	for (int i = head[u]; i != -1; i = e[i].next) {
		int v = e[i].v;
		if (v != p && !del[v]) {
			sum = size[v], root = 0;
			find(v, u), divide(root, u);
		}
	}
}

int lca(int u, int v)
{
	u = pos[u], v = pos[v];

	if (u > v)
		swap(u, v);
	int t = lg[v - u + 1];

	return min(st[u][t], st[v - bin[t] + 1][t]);
}

int dis(int u, int v)
{
	return deep[u] + deep[v] - 2 * lca(u, v);
}

void turn_off(int u, int p)
{
	if (u == p) {
		B[u].push(0);
		if (B[u].size() == 2)
			A.push(B[u].first());
	}

	if (!fa[p])
		return;

	int f = fa[p], d = dis(u, f), tmp = C[p].first();

	C[p].push(d);

	if (d > tmp) {
		int mx = B[f].first() + B[f].second(),
		    size = B[f].size();

		B[f].push(d);

		if (tmp)
			B[f].erase(tmp);

		int now = B[f].first() + B[f].second();

		if (now > mx) {
			if (size >= 2)
				A.erase(mx);
			if (B[f].size() >= 2)
				A.push(now);
		}
	}

	turn_off(u, f);
}

void turn_on(int u, int p)
{
	if (u == p) {
		if (B[u].size() == 2)
			A.erase(B[u].first());
		B[u].erase(0);
	}

	if (!fa[p])
		return;
	
	int f = fa[p], d = dis(u, f), tmp = C[p].first();

	C[p].erase(d);

	if (d == tmp) {
		int mx = B[f].first() + B[f].second(),
		    size = B[f].size();

		B[f].erase(d);
		
		if (C[p].first())
			B[f].push(C[p].first());

		int now = B[f].first() + B[f].second();

		if (now < mx) {
			if (size >= 2)
				A.erase(mx);
			if (B[f].size() >= 2)
				A.push(now);
		}
	}

	turn_on(u, f);
}	

void init()
{
	bin[0] = 1;
	for (int i = 1; i <= 20; i++)
		bin[i] = bin[i - 1] << 1;

	lg[0] = -1;
	for (int i = 1; i <= 200000; i++)
		lg[i] = lg[i >> 1] + 1;
}

int main()
{
	n = read(), init();

	memset(head, -1, sizeof head);	
	for (int i = 1; i < n; i++) {
		int u = read(), v = read();
		insert(u, v);
	}

	dfs(1, 0);
	for (int i = 1; i <= 20; i++)
		for (int j = 1; j <= dfn; j++)
			if (j + bin[i] - 1 <= dfn)
		st[j][i] = min(st[j][i - 1], st[j + bin[i - 1]][i - 1]);

	sm[0] = inf, root = 0, sum = n;
	find(1, 0), divide(root, 0);

	for (int i = 1; i <= n; i++)
		C[i].push(0), col[i] = 1;

	for (int i = 1; i <= n; i++)
		turn_off(i, i);

	m = read(), tot = n;

	while (m--) {
		char s[10]; scanf("%s", s);

		if (s[0] == 'G') {
			if (tot <= 1)
				printf("%d\n", tot - 1);
			else
				printf("%d\n", A.first());
		}

		if (s[0] == 'C') {
			int w = read();

			if (col[w] == 1)
				tot--, turn_on(w, w);
			if (col[w] == 0)
				tot++, turn_off(w, w);

			col[w] ^= 1;
		}
	}

	return 0;
}

你可能感兴趣的:(BZOJ1095【动态点分治】【优先队列】)