题目链接
给定一棵 n 个点的带边权的树,点从 1 到 n 编号。每个点可能有两种颜色:黑或白。我们定义 dist(a,b) 为点 a 至点 b 路径上的权值之和。
一开始所有的点都是白色的。
要求作以下操作:
C a
将点 a 的颜色反转。(黑变白,白变黑)
A
询问 dist(a,b) 的最大值。a,b 点都必须为白色(a 与 b 可以相同),显然如果树上仍存在白点,查询得到的值一定是个非负数。
特别地,如果 A
操作时树上没有白点,输出 They have disappeared.
。
这里讲一下关于LCT的做法,确实不大好写,和不大好想。
参考资料:https://www.luogu.com.cn/blog/Minamoto/solution-sp2666
前置知识
要知道基础的知识,LCT是多个Splay通过虚边相连的森林,每个Splay都是一条链。
假设并固定树的根
我们假设树的根是1,于是可以把其他的所有的边的权值都放到点上去了,因为LCT是无法记录边的信息的,但是可以维护点权,我们假设一开始的每个Splay都是有且仅有自己本身这个点,将边的信息存到了点上去,保证了维护了边的信息。
Splay树与Splay树的传递
树与树的信息之间要保证传递的话,肯定是要用一些数据结构来维护虚边的,因为对于Splay实际上还是一棵二叉树,所以最多维护两个结点的信息,而多出来的结点要通过堆来进行传递。
但是Splay与Splay树之间的信息呢?有时候的树可能是这样的:
那么,如果是从4这个点到5这号点的边存在的话,应该如何去更新呢?
我假设存这样的两个东西,表示以x为Splay的root的这棵Splay树的最浅的结点到最远的白点的距离,表示以x为Splay的root的这棵Splay树的最深的结点到最远的白点的距离,这样,当信息在两棵Splay之间传递的时候,就可以利用虚点的数据结构来维护了。
- 在一棵Splay树上的结点的信息的传递
- 可以是左子树的直接继承
- 也可以通过以x为根的Splay子树的最浅的结点到x点的距离:,这里的是x点的状态(是白点就为0,不然就是-INF说明不能将它作为白点的端点)
- 还可以继续向x的右儿子延伸,先看实边,于是,因为深度的连续性关系(LCT的Splay必然是原树上的一条链),我们可以取来保证了连续,因为rc的最浅一定就是x的直接相连的点,
- 对于虚边来更新,虚边的Splay中的最浅的点一定是和x直接相连的,所以我们可以开一个堆,来维护最大值,存进所有虚边的,最后只用去找虚边的最大的就可以了,所以假设这里用来表示这个堆(每个点开一个),于是就是
知晓了在Splay树上的信息的维护,接下去我们可以推一下的信息了,在细节上还是略有些不同的,区别就在于x,如果从更浅的点到x,那么必然会经过x的父亲到x的这条边,所以要加上val[x],但是走深度大于x的点,就不一定会经过x和x的父亲的这条边了,所以,在这里要细节的对待val[x]这条信息,我下面简单的写一下:
- 直接继承
- 这里就不需要加“val[x]”了,是因为在x点就停下了
- 从更浅的点,必然经过val[x]
- 去往其他深度深的点,以x为中间结点,也就是x作为深度最浅,从rc过来,去往另一个深度更深的方向,这里肯定会去往另外的虚边,因为深度更深,所以还是利用就可以了,
记录答案
上面讲了那么多信息的更新,却迟迟没有提到如何去记录答案。
答案会是有几种可能?
- 对于一个Splay,可能是由它的左子树的最深结点的最远距离的白点到右子树的最浅结点所能到达的白点,此时要经过x和x的父亲的这条“val[x]”的边
- 也可能答案在左子树的Splay或者右子树的Splay中出现了,所以要去记录每棵子树的可能答案
- 也有可能答案存在于虚点之中,所以还要再开一个堆来维护虚点的答案,用以继承
- 如果x是个白点的话,也有可能是x到虚点的Splay中的最浅点的最远白点的距离也就是
Access()函数
LCT的精髓就在于此,因为有且只有它会是的虚边和实边进行互换。
首先,维护的是上看提到的和,分别是“虚Splay中的最浅的点所能到达的最远的白点的距离”、“虚点Splay的答案,用来做传递使用”。
在改变实虚的时候,不要忘记删去原有的,然后再引进新的虚,虚实转换。
初始化
这里要特别讲一下初始化,是为什么?是因为我们用1来假定根,使得信息维护从边转移到了结点上了,将边权信息化作点权信息。
这里会产生虚边,于是就要做一个处理了,对于虚边,不要忘记把信息放进和中去。也不要忘记pushup()。
Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e5 + 7;
//const int maxN = 5;
int N, Q, white, c[maxN][2], r[maxN], fa[maxN], size[maxN], col[maxN], lmx[maxN], rmx[maxN], mxs[maxN], w[maxN], val[maxN], ans;
struct heap
{
priority_queue<int> Que, Del;
inline bool empty()
{
while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
return Que.empty();
}
inline void push(int val) { Que.push(val); }
inline void clear(int val) { Del.push(val); }
inline int size() { return (int)(Que.size() - Del.size()); }
inline int top()
{
while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
return !Que.empty() ? Que.top() : -INF;
}
inline void pop()
{
while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
Que.pop();
}
inline int sec()
{
if(!empty())
{
int tmp = top(), re = -INF; pop();
if(!empty())
{
re = top();
}
push(tmp);
return re;
}
else return -INF;
}
} s[maxN], anss[maxN];
inline bool isroot(int x) { return c[fa[x]][0] != x && c[fa[x]][1] != x; }
inline void pushup(int x)
{
if(!x) return;
size[x] = size[c[x][0]] + size[c[x][1]] + val[x];
lmx[x] = max(lmx[c[x][0]], size[c[x][0]] + max(w[x], max(s[x].top(), lmx[c[x][1]])) + val[x]);
rmx[x] = max(rmx[c[x][1]], size[c[x][1]] + max(w[x], max(s[x].top(), rmx[c[x][0]] + val[x])));
int L = max(max(w[x], s[x].top()), rmx[c[x][0]] + val[x]), R = max(max(w[x], s[x].top()), lmx[c[x][1]]) + val[x];
mxs[x] = max(lmx[c[x][1]] + L, rmx[c[x][0]] + R);
mxs[x] = max(mxs[x], max(mxs[c[x][0]], mxs[c[x][1]]));
mxs[x] = max(mxs[x], anss[x].top());
mxs[x] = max(mxs[x], s[x].top() + s[x].sec());
if(!w[x]) mxs[x] = max(mxs[x], max(0, s[x].top()));
}
inline void pushr(int x)
{
if(!x) return;
swap(c[x][0], c[x][1]);
r[x] ^= 1;
}
inline void pushdown(int x)
{
if(!x) return;
if(r[x])
{
pushr(c[x][0]);
pushr(c[x][1]);
r[x] = 0;
}
}
void Rotate(int x)
{
int y = fa[x], z = fa[y], k = c[y][1] == x, cop = c[x][k ^ 1];
if(!isroot(y)) c[z][c[z][1] == y] = x;
fa[x] = z;
c[y][k] = cop;
fa[cop] = y;
c[x][k ^ 1] = y;
fa[y] = x;
pushup(y); pushup(x);
}
int Stap[maxN];
void Splay(int x)
{
int y = x, z = 0;
Stap[++z] = y;
while(!isroot(y)) Stap[++z] = y = fa[y];
while(z) pushdown(Stap[z--]);
while(!isroot(x))
{
y = fa[x]; z = fa[y];
if(!isroot(y)) (c[z][0] == y) ^ (c[y][0] == x) ? Rotate(x) : Rotate(y);
Rotate(x);
}
}
void access(int x)
{
int y = 0;
while(x)
{
Splay(x);
if(c[x][1])
{
s[x].push(lmx[c[x][1]]);
anss[x].push(mxs[c[x][1]]);
}
if(y)
{
s[x].clear(lmx[y]);
anss[x].clear(mxs[y]);
}
c[x][1] = y;
pushup(x);
y = x; x = fa[x];
}
}
int head[maxN], cnt;
struct Eddge
{
int nex, to, val;
Eddge(int a=-1, int b=0, int c=0):nex(a), to(b), val(c) {}
} edge[maxN << 1];
inline void addEddge(int u, int v, int w)
{
edge[cnt] = Eddge(head[u], v, w);
head[u] = cnt++;
}
inline void _add(int u, int v, int w) { addEddge(u, v, w); addEddge(v, u, w); }
void dfs(int u, int father)
{
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == father) continue;
fa[v] = u; val[v] = edge[i].val;
dfs(v, u);
s[u].push(lmx[v]);
anss[u].push(mxs[v]);
}
pushup(u);
}
void update(int x)
{
access(x);
Splay(x);
col[x] ^= 1;
w[x] = col[x] ? 0 : -INF;
pushup(x);
ans = mxs[x];
if(col[x]) white++;
else white--;
}
inline int query(int x = 1)
{
access(x); Splay(x);
return anss[x].top();
}
inline void init()
{
white = N; lmx[0] = rmx[0] = mxs[0] = -INF;
for(int i=1; i<=N; i++)
{
r[i] = 0; c[i][0] = c[i][1] = 0; head[i] = -1; col[i] = 1; //all white begin
size[i] = 1;
w[i] = 0;
}
}
int main()
{
scanf("%d", &N);
init();
for(int i=1, u, v, w; i<N; i++)
{
scanf("%d%d%d", &u, &v, &w);
_add(u, v, w);
}
val[1] = 0;
dfs(1, 0);
ans = mxs[1];
scanf("%d", &Q);
char op[3]; int x;
while(Q--)
{
scanf("%s", op);
if(op[0] == 'C')
{
scanf("%d", &x);
update(x);
}
else
{
if(!white) printf("They have disappeared.\n");
else printf("%d\n", ans);
}
}
return 0;
}