题目:
http://acm.hdu.edu.cn/showproblem.php?pid=4010
题意:
给定一个有n个点的树,有以下四种操作:
- 1 x y: 如果x y不在同一棵树上,那么在它们中间新建一条边,把他们连接起来,否则操作非法
- 2 x y:如果x y在同一棵树上,那么把x替换为树根并且把y和y的父亲之间的边删掉,否则操作非法
- 3 w x y:如果x y在同一棵树上,那么把xy路径上所有点的点权加上w,否则操作非法
- 4 x y:如果x y在同一棵树上,查询x y路径上的最大点权,否则操作非法
- 注意,非法操作都输出−1,无论是不是查询
思路:
直接LCT啊。。。我好像老把数据结构写搓,写搓了之后还不会debug,真是一场灾难,搞得我怀疑人生。。。
#include <bits/stdc++.h>
using namespace std;
const int N = 300000 + 10, INF = 0x3f3f3f3f;
struct edge
{
int to, next;
}g[N*2];
int cnt, head[N];
int son[N][2], fat[N], key[N], maxval[N], rev[N], lazy[N];
int top, stk[N];
void init()
{
cnt = 0;
memset(head, -1, sizeof head);
memset(son, 0, sizeof son);
memset(key, 0, sizeof key);
memset(fat, 0, sizeof fat);
memset(rev, 0, sizeof rev);
memset(lazy, 0, sizeof lazy);
memset(maxval, 0, sizeof maxval);
}
void add_edge(int v, int u)
{
g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;
}
void dfs(int v, int fa)
{
fat[v] = fa;
for(int i = head[v]; ~i; i = g[i].next)
{
int u = g[i].to;
if(u == fa) continue;
dfs(u, v);
}
}
bool is_root(int x)
{
return son[fat[x]][0] != x && son[fat[x]][1] != x;
}
void push_up(int x)
{
maxval[x] = max(key[x], max(maxval[son[x][0]], maxval[son[x][1]]));
}
void push_down(int x)
{
if(lazy[x])
{//注意下放lazy标记时,如果不判断x的左右儿子是否存在而直接下放,相当于是下放到0这个点上,树上有很多点儿子为空都连接0,就会干扰到这些点,导致出现错误。。。
if(son[x][0])
{
lazy[son[x][0]] += lazy[x];
key[son[x][0]] += lazy[x];
maxval[son[x][0]] += lazy[x];
}
if(son[x][1])
{
lazy[son[x][1]] += lazy[x];
key[son[x][1]] += lazy[x];
maxval[son[x][1]] += lazy[x];
}
lazy[x] = 0;
}
if(rev[x])
{//翻转标记不用判断左右儿子是否存在
swap(son[x][0], son[x][1]);
rev[son[x][0]] ^= 1, rev[son[x][1]] ^= 1;
rev[x] ^= 1;
}
}
void Rotate(int x)
{
int y = fat[x], p = son[y][0] == x;
son[y][!p] = son[x][p], fat[son[x][p]] = y;
if(! is_root(y)) son[fat[y]][son[fat[y]][1]==y] = x;
fat[x] = fat[y];
son[x][p] = y, fat[y] = x;
push_up(y);
}
void splay(int x)
{
top = 0;
stk[++top] = x;
for(int i = x; !is_root(i); i = fat[i]) stk[++top] = fat[i];
for(int i = top; i >= 1; i--) push_down(stk[i]);
while(! is_root(x))
{
int y = fat[x], z = fat[y];
if(is_root(y)) Rotate(x);
else
{
if((x == son[y][0]) ^ (y == son[z][0])) Rotate(x), Rotate(x);
else Rotate(y), Rotate(x);
}
}
push_up(x);
}
void access(int x)
{
int y = 0;
while(x)
{
splay(x);
son[x][1] = y;
push_up(x);
y = x, x = fat[x];
}
}
int find_root(int x)
{
access(x); splay(x);
while(son[x][0]) x = son[x][0];
return x;
}
bool check(int x, int y)
{
return find_root(x) == find_root(y);
}
void make_root(int x)
{
access(x); splay(x);
rev[x] ^= 1;
}
void link(int x, int y)
{
if(check(x, y))
{
printf("-1\n"); return;
}
make_root(x); fat[x] = y;
}
void cut(int x, int y)
{
if(x == y || !check(x, y))
{
printf("-1\n"); return;
}
make_root(x);
access(y); splay(y);
son[y][0] = fat[son[y][0]] = 0;
push_up(y);
}
void update(int x, int y, int v)
{
if(!check(x, y))
{
printf("-1\n"); return;
}
make_root(x);
access(y); splay(y);
lazy[y] += v, maxval[y] += v, key[y] += v;//此时y的右子树为空,所以可以这样更新
}
int query(int x, int y)
{
if(!check(x, y)) return -1;
make_root(x);
access(y); splay(y);
return maxval[y];
}
int main()
{
int n, m, opt, x, y, z;
while(~ scanf("%d", &n))
{
init();
for(int i = 1; i <= n-1; i++)
{
scanf("%d%d", &x, &y);
add_edge(x, y); add_edge(y, x);
}
for(int i = 1; i <= n; i++) scanf("%d", &key[i]), maxval[i] = key[i];
dfs(1, 0);
scanf("%d", &m);
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &opt, &x, &y);
if(opt == 1) link(x, y);
else if(opt == 2) cut(x, y);
else if(opt == 3)
{
scanf("%d", &z);
update(y, z, x);
}
else printf("%d\n", query(x, y));
}
printf("\n");
}
return 0;
}