RT 初学 LCT 维护子树信息,估计会有很多问题,比如样例都过不去,但我觉得这个整体思路应该能写,大概思路就是用虚子树维护个子树权值和,然后还用虚子树每个点维护一下它所有子树的权值和的平方,最后询问的时候 makeroot 一下。求一个 LCT 带师解答。
为啥在 NOIp 之前做这种题?属于是摆了。
#include <cstdio>
#include <algorithm>
const int N = 2e5 + 10; typedef long long ll; int st[N], tp;
struct LCT
{
#define Fa(x) (node[x].fa)
#define Ls(x) (node[x].ch[0])
#define Rs(x) (node[x].ch[1])
struct Splay{ int fa, ch[2], sum, ssum, w, revTag; ll ans, sans; }node[N];
void pushup(int x)
{
node[x].sum = node[Ls(x)].sum + node[Rs(x)].sum + node[x].w + node[x].ssum;
node[x].ans = node[Ls(x)].ans + node[Rs(x)].ans + node[x].sans + (ll)node[x].sum * node[x].sum;
}
void reverse(int x) { std::swap(Ls(x), Rs(x)); node[x].revTag ^= 1; }
void pushdown(int x)
{
if (!node[x].revTag) return ;
if (Ls(x)) reverse(Ls(x)); if (Rs(x)) reverse(Rs(x));
node[x].revTag = 0;
}
int get(int x) { return Rs(Fa(x)) == x; }
int nRoot(int x) { return Rs(Fa(x)) == x || Ls(Fa(x)) == x; }
void rotate(int x)
{
int fa = Fa(x), gf = Fa(fa), d = get(x), dd = get(fa);
if (nRoot(fa)) node[gf].ch[dd] = x;
node[fa].ch[d] = node[x].ch[d ^ 1]; Fa(node[x].ch[d ^ 1]) = fa;
node[x].ch[d ^ 1] = fa; Fa(fa) = x; Fa(x) = gf;
pushup(fa); pushup(x);
}
void splay(int x)
{
int y = st[tp = 1] = x;
while (nRoot(y)) st[++tp] = y = Fa(y);
while (tp) pushdown(st[tp--]);
for (; nRoot(x); rotate(x))
if (nRoot(Fa(x))) rotate(get(x) == get(Fa(x)) ? Fa(x) : x);
pushup(x);
}
void access(int x)
{
int y = 0;
while (x)
{
splay(x);
if (Rs(x))
{
node[x].ssum += node[Rs(x)].sum;
node[x].sans += node[Rs(x)].ans;
}
Rs(x) = y;
if (y)
{
node[x].ssum -= node[y].sum;
node[x].sans -= node[y].ans;
}
pushup(x); x = Fa(y = x);
}
}
void makeroot(int x) { access(x); splay(x); reverse(x); }
void link(int x, int y)
{
access(y); splay(y); splay(x); Fa(x) = y;
node[y].ssum += node[x].sum;
node[y].sans += node[x].ans;
pushup(y);
}
}lct;
int a[N], b[N];
int main()
{
int n, q; scanf("%d%d", &n, &q);
for (int i = 1; i < n; ++i) scanf("%d%d", &a[i], &b[i]);
for (int i = 1; i <= n; ++i) scanf("%d", &lct.node[i].w);
for (int i = 1; i < n; ++i) lct.link(a[i], b[i]);
for (int i = 1, opt, x, y; i <= q; ++i)
{
scanf("%d%d", &opt, &x);
if (opt == 2) lct.makeroot(x), printf("%lld\n", lct.node[x].ans);
else scanf("%d", &y), lct.node[x].w = y, lct.splay(x);
}
return 0;
}
QAQ