原题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1036
树的统计
Description
一棵树上有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本身
Input
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
4
1
2
2
10
6
5
6
5
16
题解
打板贼6
代码
#include<bits/stdc++.h>
#define ls son[v][0]
#define rs son[v][1]
using namespace std;
const int M=3e4+5;
int sum[M],mx[M],dad[M],son[M][2],val[M],data[M][2],n,m;
bool rev[M];
bool notroot(int v){return son[dad[v]][0]==v||son[dad[v]][1]==v;}
void up(int v){sum[v]=sum[ls]+sum[rs]+val[v];mx[v]=max(val[v],max(mx[ls],mx[rs]));}
void turn(int v){swap(ls,rs);rev[v]^=1;}
void down(int v){if(rev[v]){if(ls)turn(ls);if(rs)turn(rs);rev[v]=0;}}
void push(int v){if(notroot(v))push(dad[v]);down(v);}
void spin(int v)
{
int f=dad[v],ff=dad[f],k=son[f][1]==v,w=son[v][!k];
if(notroot(f))son[ff][son[ff][1]==f]=v;
son[v][!k]=f;son[f][k]=w;
if(w)dad[w]=f;
dad[f]=v;dad[v]=ff;
up(f);up(v);
}
void splay(int v)
{
push(v);
int f,ff;
while(notroot(v))
{
f=dad[v];ff=dad[f];
if(notroot(f))spin((son[f][0]==v)^(son[ff][0]==f)?v:f);
spin(v);
}
}
void access(int v){for(int f=0;v;v=dad[f=v])splay(v),rs=f,up(v);}
void beroot(int v){access(v);splay(v);turn(v);}
void split(int x,int y){beroot(x);access(y);splay(y);}
void link(int x,int y){beroot(x);dad[x]=y;}
void in()
{
int a,b;
scanf("%d",&n);
for(int i=1;i<n;++i)
scanf("%d%d",&data[i][0],&data[i][1]);
for(int i=1;i<=n;++i)
scanf("%d",&a),val[i]=sum[i]=mx[i]=a;
for(int i=1;i<n;++i)
link(data[i][0],data[i][1]);
}
void ac()
{
mx[0]=-1e9;
char ch[10];
int a,b;
scanf("%d",&m);
for(int i=1;i<=m;++i)
{
scanf("%s%d%d",ch,&a,&b);
switch(ch[1])
{
case 'H':splay(a);val[a]=b;up(a);break;
case 'M':split(a,b);printf("%d\n",mx[b]);break;
case 'S':split(a,b);printf("%d\n",sum[b]);
}
}
}
int main()
{
in();ac();
return 0;
}