「ZJOI2008」树的统计 - LCT模板题 | Bill Yang's Blog

「ZJOI2008」树的统计 - LCT模板题

题目大意

    一棵树上有$n$个节点,编号分别为$1$到$n$,每个节点都有一个权值$w$。
    我们将以下面的形式来要求你对这棵树完成一些操作:
        I.CHANGE u t : 把结点u的权值改为t
        II.QMAX u v: 询问从点u到点v的路径上的节点的最大权值
        III.QSUM u v: 询问从点u到点v的路径上的节点的权值和
    注意:从点u到点v的路径上的节点包括u和v本身


题目分析

复习一下动态树。

动态树模板题,存一份比较优美的代码。

注意点权有负数。


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;

inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}

int max(int a,int b) {
return a>b?a:b;
}

const int maxn=30005;

struct Tree {
int child[2],father;
int val,max,sum;
bool rev;
};

struct Link_Cut_Tree {
Tree tree[maxn];
stack<int>S;
Link_Cut_Tree() {
tree[0].val=tree[0].max=-0x7fffffff/2;
}
#define ls(x) tree[x].child[0]
#define rs(x) tree[x].child[1]
#define fa(x) tree[x].father
#define rev(x) tree[x].rev
bool isroot(int index) {
return ls(fa(index))!=index&&rs(fa(index))!=index;
}
bool checkson(int index) {
return rs(fa(index))==index;
}
void push_down(int index) {
if(!rev(index))return;
rev(ls(index))^=1;
rev(rs(index))^=1;
swap(ls(index),rs(index));
rev(index)=0;
}
void push_up(int index) {
int ls=ls(index),rs=rs(index);
tree[index].max=max(max(tree[ls].max,tree[rs].max),tree[index].val);
tree[index].sum=tree[ls].sum+tree[rs].sum+tree[index].val;
}
void rotate(int index) { //两靠后异或验证
int father=fa(index),grand=fa(father),side=checkson(index);
if(!isroot(father))tree[grand].child[checkson(father)]=index;
tree[father].child[side]=tree[index].child[side^1];
fa(tree[father].child[side])=father;
fa(father)=index;
tree[index].child[side^1]=father;
fa(index)=grand;
push_up(father);
push_up(index);
}
void splay(int index) { //辅助树根退出
S.push(index);
for(int i=index; !isroot(i); i=fa(i))S.push(fa(i));
while(!S.empty())push_down(S.top()),S.pop();
for(int father; !isroot(index); rotate(index)) {
father=fa(index);
if(!isroot(father))rotate(checkson(father)==checkson(index)?father:index);
}
}
void access(int index) { //树根退出
for(int son=0; index; son=index,index=fa(index)) {
splay(index);
rs(index)=son;
push_up(index);
}
}
void reverse(int index) {
access(index);
splay(index);
rev(index)^=1;
}
void link(int x,int y) {
reverse(x);
fa(x)=y;
}
void split(int x,int y) {
reverse(x);
access(y);
splay(y);
}
void modify(int index,int v) {
splay(index);
tree[index].val=v;
push_up(index);
}
} lct;

int n,m,from[maxn],to[maxn];

int main() {
n=Get_Int();
for(int i=1; i<n; i++) {
from[i]=Get_Int();
to[i]=Get_Int();
}
for(int i=1; i<=n; i++)lct.tree[i].sum=lct.tree[i].max=lct.tree[i].val=Get_Int();
for(int i=1; i<n; i++)lct.link(from[i],to[i]);
m=Get_Int();
for(int i=1; i<=m; i++) {
char opt1=getchar(),opt2=getchar();
int x=Get_Int(),y=Get_Int();
if(opt1=='C')lct.modify(x,y);
else if(opt1=='Q'&&opt2=='M') {
lct.split(x,y);
printf("%d\n",lct.tree[y].max);
} else {
lct.split(x,y);
printf("%d\n",lct.tree[y].sum);
}
}
return 0;
}
姥爷们赏瓶冰阔落吧~
0%