HYSBZ 1095 Hide 捉迷藏

Description

  捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia、Wind和孩子们决定在家里玩
捉迷藏游戏。他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋
子都互相可达。游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯。在起初的
时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要
求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性,Jiajia希望知道可能的最远的两
个孩子的距离(即最远的两个关灯房间的距离)。 我们将以如下形式定义每一种操作: C(hange) i 改变第i个房
间的照明状态,若原来打开,则关闭;若原来关闭,则打开。 G(ame) 开始一次游戏,查询最远的两个关灯房间的
距离。

Input

  第一行包含一个整数N,表示房间的个数,房间将被编号为1,2,3…N的整数。接下来N-1行每行两个整数a, b,
表示房间a与房间b之间有一条走廊相连。接下来一行包含一个整数Q,表示操作次数。接着Q行,每行一个操作,如
上文所示。

Output

  对于每一个操作Game,输出一个非负整数到hide.out,表示最远的两个关灯房间的距离。若只有一个房间是关
着灯的,输出0;若所有房间的灯都开着,输出-1。

Sample Input

8
1 2
2 3
3 4
3 5
3 6
6 7
6 8
7
G
C 1
G
C 2
G
C 1
G

Sample Output

4
3
3
4

Hint

对于100%的数据, N ≤100000, M ≤500000。


动态树分治,每个节点维护两个set

#include<set>
#include<queue>
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
const int low(int x) { return x&-x; }
const int INF = 0x7FFFFFFF;
const int maxn = 4e5 + 10;
int n, x, y, flag[maxn], cnt;
char ch[maxn];

struct Tree
{
	int ft[maxn], nt[maxn], u[maxn], sz;
	int mx[maxn], ct[maxn], fa[maxn], vis[maxn];
	struct point
	{
		int x, y;
		point(int x = 0, int y = 0) :x(x), y(y) {}
		bool operator<(const point&a)const { return x < a.x; }
	};
	vector<point> t[maxn];
	multiset<int> p[maxn], pp[maxn], ans;
	multiset<int> ::reverse_iterator it;

	void clear(int n)
	{
		mx[sz = 0] = INF;
		ans.clear();
		for (int i = 1; i <= n; i++)
		{
			ft[i] = (vis[i] = 0) - 1;
			t[i].clear();
			p[i].clear();
			pp[i].clear();
		}
	}
	void AddEdge(int x, int y)
	{
		u[sz] = y;	nt[sz] = ft[x];	ft[x] = sz++;
		u[sz] = x;	nt[sz] = ft[y];	ft[y] = sz++;
	}
	int dfs(int x, int fa, int sum)
	{
		int y = mx[x] = (ct[x] = 1) - 1;
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			int z = dfs(u[i], x, sum);
			ct[x] += ct[u[i]];
			mx[x] = max(mx[x], ct[u[i]]);
			y = mx[y] < mx[z] ? y : z;
		}
		mx[x] = max(mx[x], sum - ct[x]);
		return mx[x] < mx[y] ? x : y;
	}
	void get(int rt, int x, int fa, int dep)
	{
		t[rt].push_back(point(x, dep));
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			get(rt, u[i], x, dep + 1);
		}
	}
	void getmax(int rt, int x, int fa, int dep)
	{
		pp[rt].insert(dep);
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			getmax(rt, u[i], x, dep + 1);
		}
	}
	int abc(int x)
	{
		if (p[x].size())
		{
			it = p[x].rbegin();
			int a = 0, b = 0;
			if (*it > 0) a = *it;
			if (p[x].size() > 1 && *(++it) > 0) b = *it;
			else if (!flag[x]) a = 0;
			return a + b;
		}
		return 0;
	}
	int aba(int x)
	{
		if (pp[x].size())
		{
			return *pp[x].rbegin();
		}
		return 0;
	}
	int build(int x, int sum, int from)
	{
		int y = dfs(x, -1, sum);
		get(y, y, -1, 0);	
		sort(t[y].begin(), t[y].end());
		fa[y] = from;	vis[y] = 1;
		for (int i = ft[y]; i != -1; i = nt[i])
		{
			if (vis[u[i]]) continue;
			int z = build(u[i], ct[u[i]] > ct[y] ? sum - ct[y] : ct[u[i]], y);
			getmax(z, u[i], y, 1);
			p[y].insert(aba(z));
		}
		ans.insert(abc(y));	vis[y] = 0;
		return y;
	}
	void change(int rt, int x, int k)
	{
		if (x == rt)
		{
			ans.erase(ans.find(abc(x)));
			flag[x] = k;
			if (k) cnt++; else cnt--;
			ans.insert(abc(x));
		}
		if (fa[x] == -1) return;
		int y = fa[x];
		int d = t[y][lower_bound(t[y].begin(), t[y].end(), point(rt, 0)) - t[y].begin()].y;
		ans.erase(ans.find(abc(y)));
		p[y].erase(p[y].find(aba(x)));
		if (!k) pp[x].erase(pp[x].find(d));	else pp[x].insert(d);
		p[y].insert(aba(x));
		ans.insert(abc(y));
		change(rt, fa[x], k);
	}
}solve;

int main()
{
	while (scanf("%d", &n) != EOF)
	{
		solve.clear(n);
		for (int i = 1; i < n; i++)
		{
			scanf("%d%d", &x, &y);
			solve.AddEdge(x, y);
		}
		for (int i = 1; i <= n; i++) flag[i] = 1, cnt = n;
		solve.build(1, n, -1);
		scanf("%d", &x);
		while (x--)
		{
			scanf("%s", ch);
			if (ch[0] == 'G')
			{
				if (cnt) printf("%d\n", *solve.ans.rbegin());
				else printf("-1\n");
			}
			else
			{
				scanf("%d", &y);
				solve.change(y, y, flag[y] ^ 1);
			}
		}
	}
	return 0;
}

用堆来代替set时间又减短了很多
#include<set>
#include<queue>
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
const int low(int x) { return x&-x; }
const int INF = 0x7FFFFFFF;
const int maxn = 4e5 + 10;
int n, x, y, flag[maxn], cnt;
char ch[maxn];

struct Tree
{
	int ft[maxn], nt[maxn], u[maxn], sz;
	int mx[maxn], ct[maxn], fa[maxn], vis[maxn];
	struct point
	{
		int x, y;
		point(int x = 0, int y = 0) :x(x), y(y) {}
		bool operator<(const point&a)const { return x < a.x; }
	};
	vector<point> t[maxn];
	struct heap
	{
		priority_queue<int> p, q;
		void clear()
		{ 
			while (!p.empty()) p.pop();
			while (!q.empty()) q.pop();
		}
		void add(int x) { p.push(x); }
		void del(int x) { q.push(x); }
		int top()
		{
			while (true)
			{
				if (p.empty()) return 0;
				else if (!q.empty() && p.top() == q.top()) p.pop(), q.pop();
				else return p.top();
			}
		}
		int toptwo(int z)
		{
			int x = top();	del(x);
			int y = top();	add(x);
			if (!y && !flag[z]) x = 0;
			return x + y;
		}
	};
	heap p[maxn], pp[maxn], ans;

	void clear(int n)
	{
		mx[sz = 0] = INF;
		ans.clear();
		for (int i = 1; i <= n; i++)
		{
			ft[i] = (vis[i] = 0) - 1;
			t[i].clear();
			p[i].clear();
			pp[i].clear();
		}
	}
	void AddEdge(int x, int y)
	{
		u[sz] = y;	nt[sz] = ft[x];	ft[x] = sz++;
		u[sz] = x;	nt[sz] = ft[y];	ft[y] = sz++;
	}
	int dfs(int x, int fa, int sum)
	{
		int y = mx[x] = (ct[x] = 1) - 1;
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			int z = dfs(u[i], x, sum);
			ct[x] += ct[u[i]];
			mx[x] = max(mx[x], ct[u[i]]);
			y = mx[y] < mx[z] ? y : z;
		}
		mx[x] = max(mx[x], sum - ct[x]);
		return mx[x] < mx[y] ? x : y;
	}
	void get(int rt, int x, int fa, int dep)
	{
		t[rt].push_back(point(x, dep));
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			get(rt, u[i], x, dep + 1);
		}
	}
	void getmax(int rt, int x, int fa, int dep)
	{
		pp[rt].add(dep);
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			getmax(rt, u[i], x, dep + 1);
		}
	}
	int build(int x, int sum, int from)
	{
		int y = dfs(x, -1, sum);
		get(y, y, -1, 0);
		sort(t[y].begin(), t[y].end());
		fa[y] = from;	vis[y] = 1;
		for (int i = ft[y]; i != -1; i = nt[i])
		{
			if (vis[u[i]]) continue;
			int z = build(u[i], ct[u[i]] > ct[y] ? sum - ct[y] : ct[u[i]], y);
			getmax(z, u[i], y, 1);
			p[y].add(pp[z].top());
		}
		ans.add(p[y].toptwo(y));	vis[y] = 0;
		return y;
	}
	void change(int rt, int x, int k)
	{
		if (x == rt)
		{
			int a, b;
			a = p[x].toptwo(x);
			flag[x] = k;
			if (k) cnt++; else cnt--;
			b = p[x].toptwo(x);
			if (a != b) ans.del(a), ans.add(b);
		}
		if (fa[x] == -1) return;
		int y = fa[x];
		int d = t[y][lower_bound(t[y].begin(), t[y].end(), point(rt, 0)) - t[y].begin()].y;

		int a = pp[x].top(), b;
		int c = p[y].toptwo(y), e;
		if (!k) pp[x].del(d); else pp[x].add(d);
		b = pp[x].top();
		if (a != b)
		{
			p[y].del(a);
			p[y].add(b);
			e = p[y].toptwo(y);
			if (c != e)
			{
				ans.del(c);
				ans.add(e);
			}
		}
		change(rt, fa[x], k);
	}
}solve;

int main()
{
	while (scanf("%d", &n) != EOF)
	{
		solve.clear(n);
		for (int i = 1; i < n; i++)
		{
			scanf("%d%d", &x, &y);
			solve.AddEdge(x, y);
		}
		for (int i = 1; i <= n; i++) flag[i] = 1, cnt = n;
		solve.build(1, n, -1);
		scanf("%d", &x);
		while (x--)
		{
			scanf("%s", ch);
			if (ch[0] == 'G')
			{
				if (cnt) printf("%d\n", solve.ans.top());
				else printf("-1\n");
			}
			else
			{
				scanf("%d", &y);
				solve.change(y, y, flag[y] ^ 1);
			}
		}
	}
	return 0;
}


去掉了查找距离的二分以后又快了一半。

#include<set>
#include<queue>
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
const int low(int x) { return x&-x; }
const int INF = 0x7FFFFFFF;
const int maxn = 4e5 + 10;
int n, x, y, flag[maxn], cnt;
char ch[maxn];

struct Tree
{
	int ft[maxn], nt[maxn], u[maxn], sz;
	int mx[maxn], ct[maxn], fa[maxn], vis[maxn];
	vector<int> t[maxn];
	struct heap
	{
		priority_queue<int> p, q;
		void clear()
		{
			while (!p.empty()) p.pop();
			while (!q.empty()) q.pop();
		}
		void add(int x) { p.push(x); }
		void del(int x) { q.push(x); }
		int top()
		{
			while (true)
			{
				if (p.empty()) return 0;
				else if (!q.empty() && p.top() == q.top()) p.pop(), q.pop();
				else return p.top();
			}
		}
		int toptwo(int z)
		{
			int x = top();	del(x);
			int y = top();	add(x);
			if (!y && !flag[z]) x = 0;
			return x + y;
		}
	};
	heap p[maxn], pp[maxn], ans;

	void clear(int n)
	{
		mx[sz = 0] = INF;
		ans.clear();
		for (int i = 1; i <= n; i++)
		{
			ft[i] = (vis[i] = 0) - 1;
			t[i].clear();
			p[i].clear();
			pp[i].clear();
		}
	}
	void AddEdge(int x, int y)
	{
		u[sz] = y;	nt[sz] = ft[x];	ft[x] = sz++;
		u[sz] = x;	nt[sz] = ft[y];	ft[y] = sz++;
	}
	int dfs(int x, int fa, int sum)
	{
		int y = mx[x] = (ct[x] = 1) - 1;
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			int z = dfs(u[i], x, sum);
			ct[x] += ct[u[i]];
			mx[x] = max(mx[x], ct[u[i]]);
			y = mx[y] < mx[z] ? y : z;
		}
		mx[x] = max(mx[x], sum - ct[x]);
		return mx[x] < mx[y] ? x : y;
	}
	void get(int x, int fa, int dep)
	{
		t[x].push_back(dep);
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			get(u[i], x, dep + 1);
		}
	}
	void getmax(int rt, int x, int fa, int dep)
	{
		pp[rt].add(dep);
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			getmax(rt, u[i], x, dep + 1);
		}
	}
	int build(int x, int sum, int from)
	{
		int y = dfs(x, -1, sum);
		fa[y] = from;	vis[y] = 1;
		for (int i = ft[y]; i != -1; i = nt[i])
		{
			if (vis[u[i]]) continue;
			int z = build(u[i], ct[u[i]] > ct[y] ? sum - ct[y] : ct[u[i]], y);
			getmax(z, u[i], y, 1);
			p[y].add(pp[z].top());
		}
		ans.add(p[y].toptwo(y));	vis[y] = 0;
		get(y, -1, 0);
		return y;
	}
	void change(int rt, int x, int k, int dep)
	{
		if (x == rt)
		{
			int a, b;
			a = p[x].toptwo(x);
			flag[x] = k;
			if (k) cnt++; else cnt--;
			b = p[x].toptwo(x);
			if (a != b) ans.del(a), ans.add(b);
		}
		if (fa[x] == -1) return;
		int y = fa[x];
		int d = t[rt][dep];

		int a = pp[x].top(), b;
		int c = p[y].toptwo(y), e;
		if (!k) pp[x].del(d); else pp[x].add(d);
		b = pp[x].top();
		if (a != b)
		{
			p[y].del(a);
			p[y].add(b);
			e = p[y].toptwo(y);
			if (c != e)
			{
				ans.del(c);
				ans.add(e);
			}
		}
		change(rt, fa[x], k, dep + 1);
	}
}solve;

int main()
{
	while (scanf("%d", &n) != EOF)
	{
		solve.clear(n);
		for (int i = 1; i < n; i++)
		{
			scanf("%d%d", &x, &y);
			solve.AddEdge(x, y);
		}
		for (int i = 1; i <= n; i++) flag[i] = 1, cnt = n;
		solve.build(1, n, -1);
		scanf("%d", &x);
		while (x--)
		{
			scanf("%s", ch);
			if (ch[0] == 'G')
			{
				if (cnt) printf("%d\n", solve.ans.top());
				else printf("-1\n");
			}
			else
			{
				scanf("%d", &y);
				solve.change(y, y, flag[y] ^ 1, 1);
			}
		}
	}
	return 0;
}
再去掉vector,又快一秒
#include<set>
#include<queue>
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
const int low(int x) { return x&-x; }
const int INF = 0x7FFFFFFF;
const int maxn = 2e5 + 10;
int n, x, y, z, f[maxn], cnt;
char ch[maxn];

struct Tree
{
	int ft[maxn], nt[maxn], u[maxn], v[maxn], sz;
	int FT[maxn], NT[maxn * 10], U[maxn * 10], V[maxn * 10], SZ;
	int mx[maxn], ct[maxn], vis[maxn];
	struct heap
	{
		priority_queue<int> p, q;
		void clear()
		{
			while (!p.empty()) p.pop();
			while (!q.empty()) q.pop();
		}
		void add(int x) { p.push(x); }
		void del(int x) { q.push(x); }
		int top()
		{
			while (true)
			{
				if (p.empty()) return -INF;
				else if (!q.empty() && p.top() == q.top()) p.pop(), q.pop();
				else return p.top();
			}
		}
		int toptwo()
		{
			int x = top();	del(x);
			int y = top();	add(x);
			if (y == -INF) return x == -INF ? x : 0;
			else return max(x + y, 0);
		}
	};
	heap p[maxn], pp[maxn], ans;

	void clear(int n)
	{
		mx[SZ = sz = 0] = INF;
		for (int i = 1; i <= n; i++)
		{
			FT[i] = ft[i] = - 1;
			f[i] = 1; vis[i] = 0;
		}
	}
	void AddEdge(int x, int y, int z)
	{
		u[sz] = y;	v[sz] = z; nt[sz] = ft[x];	ft[x] = sz++;
		u[sz] = x;	v[sz] = z; nt[sz] = ft[y];	ft[y] = sz++;
	}
	void ADDEDGE(int x, int y, int z)
	{
		U[SZ] = y;	V[SZ] = z;	NT[SZ] = FT[x];	FT[x] = SZ++;
	}
	int dfs(int x, int fa, int sum)
	{
		int y = mx[x] = (ct[x] = 1) - 1;
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			int z = dfs(u[i], x, sum);
			ct[x] += ct[u[i]];
			mx[x] = max(mx[x], ct[u[i]]);
			y = mx[y] < mx[z] ? y : z;
		}
		mx[x] = max(mx[x], sum - ct[x]);
		return mx[x] < mx[y] ? x : y;
	}
	void find(int rt, int x, int fa, int len)
	{
		ADDEDGE(x, rt, len);
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			find(rt, u[i], x, len + v[i]);
		}
	}
	void get(int rt, int x, int fa, int len)
	{
		pp[rt].add(len);
		for (int i = ft[x]; i != -1; i = nt[i])
		{
			if (vis[u[i]] || u[i] == fa) continue;
			get(rt, u[i], x, len + v[i]);
		}
	}
	int build(int x, int sum)
	{
		int y = dfs(x, -1, sum);
		find(y, y, -1, 0);	vis[y] = 1;
		p[y].clear();	p[y].add(0);
		for (int i = ft[y]; i != -1; i = nt[i])
		{
			if (vis[u[i]]) continue;
			int z = build(u[i], ct[u[i]] > ct[y] ? sum - ct[y] : ct[u[i]]);
			pp[z].clear(); 
			get(z, u[i], y, v[i]);
			p[y].add(pp[z].top());
		}
		ans.add(p[y].toptwo()); vis[y] = 0;
		return y;
	}
	void change(int x)
	{
		if (f[x] ^= 1) ++cnt; else --cnt;
		int a = p[x].toptwo(), b, c, d;
		f[x] ? p[x].add(0) : p[x].del(0);
		b = p[x].toptwo();
		if (a != b) ans.del(a), ans.add(b);
		for (int i = FT[x]; NT[i] != -1; i = NT[i])
		{
			int y = U[i], z = U[NT[i]], len = V[NT[i]];
			a = pp[y].top();
			f[x] ? pp[y].add(len) : pp[y].del(len);
			b = pp[y].top();
			if (a != b)
			{
				c = p[z].toptwo();
				p[z].del(a), p[z].add(b);
				d = p[z].toptwo();
				if (c != d) ans.del(c),ans.add(d);
			}	
		}
	}
}solve;

int main()
{
	while (scanf("%d", &n) != EOF)
	{
		solve.clear(cnt = n);
		for (int i = 1; i < n; i++)
		{
			scanf("%d%d", &x, &y);
			solve.AddEdge(x, y, 1);
		}
		solve.build(1, n);
		scanf("%d", &x);
		while (x--)
		{
			scanf("%s", ch);
			if (ch[0] == 'G')
			{
				if (cnt) printf("%d\n", solve.ans.top());
				else printf("They have disappeared.\n");
			}
			else
			{
				scanf("%d", &y);
				solve.change(y);
			}
		}
	}
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值