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;
}