题目来源
http://www.tyvj.cn/p/4071
题目大意
- 给定一棵树,支持修改单点的权值和查询某一路径上权值最大的点,总点数不超过100000。
题解
- 反正是要退役了,LCT这种东西NOIP是用不到了,就拿这个题和这种优美的数据结构说再见吧。
- LCT维护每条实链上权值最大的点。单点修改时先access,再splay,然后直接改,再维护一下实链上权值最大的点的下标就可以了。查询时先把第一个点置为根,再access并splay第二个点,然后第二个点所在实链上点权最大的那个点即为答案。
- 这是很基础的LCT操作了,连化边为点都没用上。
Code
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 100005
#define nil 0
using namespace std;
int n, root, q;
bool rev[N];
int val[N], mx[N], fa[N], lc[N], rc[N];
int S[N];
inline void update(int x)
{
mx[x] = x;
if(lc[x] != nil) if(val[mx[lc[x]]] > val[mx[x]]) mx[x] = mx[lc[x]];
if(rc[x] != nil) if(val[mx[rc[x]]] > val[mx[x]]) mx[x] = mx[rc[x]];
}
inline void pushdown(int x)
{
if(rev[x])
{
swap(lc[x], rc[x]);
rev[lc[x]] ^= 1; rev[rc[x]] ^= 1;
rev[x] = false;
}
}
void zig(int x)
{
int y = fa[x];
lc[y] = rc[x];
fa[rc[x]] = y;
rc[x] = y;
fa[x] = fa[y];
if(y == lc[fa[y]]) lc[fa[y]] = x;
else if(y == rc[fa[y]]) rc[fa[y]] = x;
fa[y] = x;
update(y);
}
void zag(int x)
{
int y = fa[x];
rc[y] = lc[x];
fa[lc[x]] = y;
lc[x] = y;
fa[x] = fa[y];
if(y == lc[fa[y]]) lc[fa[y]] = x;
else if(y == rc[fa[y]]) rc[fa[y]] = x;
fa[y] = x;
update(y);
}
void splay(int x)
{
int top = 0;
S[top++] = x;
for(int i = x; i == lc[fa[i]] || i == rc[fa[i]]; i = fa[i])
{
S[top++] = fa[i];
}
while(top--) pushdown(S[top]);
int y = nil, z = nil;
while(x == lc[fa[x]] || x == rc[fa[x]])
{
y = fa[x]; z = fa[y];
if(x == lc[y])
{
if(y == lc[z]) zig(y);
zig(x);
}
else
{
if(y == rc[z]) zag(y);
zag(x);
}
}
update(x);
}
inline int access(int x)
{
int y = nil;
for(y = nil; x != nil; y = x, x = fa[x])
{
splay(x);
rc[x] = y;
update(x);
}
return y;
}
inline int getLCA(int x, int y)
{
access(x);
return access(y);
}
inline void makeroot(int x)
{
access(x); splay(x);
rev[x] ^= 1;
}
inline void lnk(int x, int y)
{
makeroot(x);
fa[x] = y;
}
inline void cut(int x, int y)
{
makeroot(x);
access(y); splay(y);
fa[x] = lc[y] = nil;
update(y);
}
inline int query(int x, int y)
{
makeroot(x);
access(y); splay(y);
return mx[y];
}
void init()
{
scanf("%d", &n);
int a, b;
for(int i = 1; i <= n; ++i) mx[i] = i;
for(int i = 1; i < n; ++i)
{
scanf("%d%d", &a, &b);
lnk(a, b);
}
scanf("%d", &q);
}
void work()
{
char opt[5];
int a, b, ansl, ansf, lca;
scanf("%d", &q);
while(q--)
{
scanf("%s", opt);
switch(opt[0])
{
case 'I': scanf("%d%d", &a, &b);
access(a); splay(a);
val[a] += b;
update(a);
break;
case 'G': scanf("%d%d", &a, &b);
printf("%d\n", val[query(a, b)]);
default : break;
}
}
}
int main()
{
init();
work();
return 0;
}
或许是最后一次叫你的全名了,再见,Link-Cut-Tree!