树是任意两点间仅有一条路径的联通图,树上的一条链定义为两个点之间的路径。在本题中定义一条链的长度为链上所有点的权值和。现有一棵带点权树,要对它进行一些操作,请你在第一次操作前和每一次操作后输出这棵树的最长链。
LCT splay的时候判GF 是!isroot(F) 下次注意
这题非常不错的虚边维护儿子信息的LCT,并且,利用LCT splay 维护的是链的性质,可以动态的利用最大子段和的方式进行合并,主要思想就是维护以x节点为根的子树所表示的链的从头开始的最大子段,从尾向前的最大子段(为了reverse),动态的合并其虚儿子的信息求出答案.
套路:LCT维护的是路径信息,序列上能做的,基本都能搬到LCT上来做,剩下的路径统计可以利用数据结构维护虚边.
代码:
%:pragma GCC optimize(4)
%:pragma GCC optimize("inline")
#include
using namespace std;
const int N = 1e5 + 5;
int min(int x , int y) {
return (x < y) ? x : y;
}
int max(int x , int y) {
return (x > y) ? x : y;
}
#define lc ch[x][0]
#define rc ch[x][1]
struct NODE {
int LMAX , RMAX , S , MAX;
}C , T[N];
multiset <int> Cl[N] , Cm[N];
multiset <int> ::reverse_iterator IT;
bool rev[N];
int n , m , x , y , rt , ch[N][2] , fa[N] , val[N] , u[N] , v[N];
inline NODE operator + (NODE A , NODE B) {
C.S = A.S + B.S;
C.LMAX = max(A.S + B.LMAX , A.LMAX);
C.RMAX = max(B.RMAX , B.S + A.RMAX);
C.MAX = max(A.MAX , max(B.MAX , A.RMAX + B.LMAX));
return C;
}
inline int get(int x) {
if(!Cl[x].size()) return 0;
return *Cl[x].rbegin();
}
inline int get2(int x) {
if(Cl[x].size() < 2) return get(x);
IT = Cl[x].rbegin();
return*IT+*(++ IT);
}
inline void up(int x) {
NODE &D = T[x];
D.S = D.MAX = D.LMAX = D.RMAX = 0;
D.S = val[x];
D.MAX = D.LMAX = D.RMAX = max(max(val[x] , 0) , get(x) + val[x]);
D.MAX = max(get2(x) + val[x] , max(D.MAX , (Cm[x].size()) ? (*Cm[x].rbegin()) : 0));
if(lc) D = T[lc] + D;
if(rc) D = D + T[rc];
}
inline void pt(int x) {
rev[x] ^= 1;
swap(lc , rc);
swap(T[x].LMAX , T[x].RMAX);
}
inline void pd(int x) {
if(rev[x]) {
if(lc)pt(lc); if(rc)pt(rc);
rev[x] = 0;
}
}
inline bool dir(int x) {
return ch[fa[x]][1] == x;
}
#define isroot(x) (ch[fa[x]][1] != x && ch[fa[x]][0] != x)
inline void dn(int x) {
if(!isroot(x)) dn(fa[x]);
pd(x);
}
int Dx , f , Df , GF;
inline void rotate(int x) {
Dx = dir(x) , f = fa[x] , Df = dir(fa[x]) , GF = fa[f];
if(!isroot(f)) ch[GF][Df] = x; fa[x] = GF; fa[f] = x; if(ch[x][!Dx]) fa[ch[x][!Dx]] = f;
ch[f][Dx] = ch[x][!Dx]; ch[x][!Dx] = f; up(f); up(x);
}
inline void splay(int x) {
dn(x);
while(!isroot(x)) {
if(isroot(fa[x])) {
rotate(x); return;
}
if(dir(x) == dir(fa[x])) rotate(fa[x]) , rotate(x);
else rotate(x) , rotate(x);
}
}
#define del(K , P) K.erase(K.find(P))
inline void A(int x , int y , int oh) {
if(oh == 1) {
Cl[x].insert(T[y].LMAX);
Cm[x].insert(T[y].MAX);
}
else {
del(Cl[x] , T[y].LMAX);
del(Cm[x] , T[y].MAX);
}
}
inline void access(int x) {
int t = 0;
for(;x;t = x , x = fa[x]){
splay(x);
if(rc)A(x , rc , 1);
if(t) A(x , t , -1);
rc = t; up(x);
}
}
inline void make_root(int x) {
access(x);splay(x); pt(x); rt = x;
}
inline void link(int x , int y) {
make_root(x);make_root(y);fa[y] = x;A(x , y , 1); up(x);rt = x;
}
inline void cut(int x , int y) {
make_root(x); access(y); splay(y); ch[y][0] = fa[x] = 0; up(y);
}
inline int getans(void) {
access(rt); return T[rt].MAX;
}
char ty[23];
bool is;
void read(int &x) {
char ch = getchar(); x = 0; is = 0;
while(!isdigit(ch)) {
if(ch == '-') is = 1; ch = getchar();
}
while(isdigit(ch)) x = x * 10 + ch - '0' , ch = getchar();
if(is) x = -x;
}
main(void) {
read(n); read(m);
register int i;
for(i = 1;i < n;++ i) read(u[i]) , read(v[i]);
for(i = 1;i <= n;++ i) read(val[i]) , up(i);
for(i = 1;i < n;++ i) link(u[i] , v[i]);
printf("%d\n" , getans());
for(i = 1;i <= m;++ i) {
scanf("%s" , ty);
if(ty[0] == 'M') {
read(x); read(y);
make_root(x); val[x] = y;
}
else {
read(x); read(y); cut(x , y);
read(x); read(y); link(x , y);
}
printf("%d\n" , getans());
}
}