Description
Input
Output
Sample Input
4 5
1 3 2 5
1 2
1 3
2 4
4 2 4
1 2 4
2 3 4
3 1 4 1
4 1 4
Sample Output
16/3
6/1
HINT
对于所有数据满足 1<=N<=50,000 1<=M<=50,000 1<=Ai<=10^6 1<=D<=100 1<=U,V<=N
Solution
以后打tag都打即时tag
注意push_down的时候不要对null作修改
建LCT的时候按输入一个一个link会T,random_shuffle一下可以有效加快速度,直接dfs更快
Code
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
typedef long long ll;
template<typename T> inline void read(T &x){
x = 0; T f = 1; char ch = getchar();
while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
while (isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
x *= f;
}
const int N = 51000;
struct Node{
Node *c[2], *fa;
ll val, sz, sum[3], exp;
bool rev_mark; ll add_mark;
inline int d(){
if (fa->c[0] != this && fa->c[1] != this) return -1;
return fa->c[1] == this;
}
inline void sc(Node *p, int d) { c[d] = p; p->fa = this; }
inline void push_up(){
sz = c[0]->sz + c[1]->sz + 1;
sum[0] = c[0]->sum[0]+c[1]->sum[0]+val;
sum[1] = c[0]->sum[1]+c[1]->sum[1]+(c[0]->sz+1)*(val+c[1]->sum[0]);
sum[2] = c[0]->sum[2]+c[1]->sum[2]+(c[1]->sz+1)*(val+c[0]->sum[0]);
exp = c[0]->exp+c[1]->exp+(c[0]->sz+1)*(c[1]->sz+1)*val+(c[1]->sz+1)*c[0]->sum[1]+(c[0]->sz+1)*c[1]->sum[2];
}
inline void add(ll dt){
val += dt;
sum[0] += sz*dt;
sum[1] += dt*sz*(sz+1)/2; sum[2] += dt*sz*(sz+1)/2;
exp += dt*sz*(sz+1)*(sz+2)/6;
add_mark += dt;
}
inline void reverse(){ swap(sum[1], sum[2]); swap(c[0], c[1]), rev_mark ^= 1; }
void push_down();
}pool[N<<1], *null=pool, *tail=pool+1, *loc[N];
void Node :: push_down(){
if (fa->c[0] == this || fa->c[1] == this) fa->push_down();
if (rev_mark){
c[0]->reverse();
c[1]->reverse();
rev_mark = 0;
}
if (add_mark){
if (c[0] != null) c[0]->add(add_mark);
if (c[1] != null) c[1]->add(add_mark);
add_mark = 0;
}
}
int n, q;
struct Edge{ int v; Edge *nxt; }POOL[N<<1], *TAIL=POOL, *g[N];
inline void setnull(){
null->c[0] = null->c[1] = null->fa = null;
null->sz = null->sum[0] = null->sum[1] = null->sum[2] = null->val = null->exp = 0;
null->add_mark = null->rev_mark = 0;
}
inline Node *newNode(ll dt){
tail->c[0] = tail->c[1] = tail->fa = null; tail->sz = 1;
tail->sum[0] = tail->sum[1] = tail->sum[2] = tail->val = tail->exp = dt;
tail->add_mark = tail->rev_mark = 0;
return tail++;
}
void rot(Node *x){
Node *y = x->fa; int d = x->d();
if (y->d() == -1) x->fa = y->fa; else y->fa->sc(x, y->d());
y->sc(x->c[!d], d); y->push_up();
x->sc(y, !d);
}
void splay(Node *x){
for (x->push_down(); x->d() != -1; ){
if (x->fa->d() == -1) rot(x);
else x->d() == x->fa->d() ?
(rot(x->fa), rot(x)) : (rot(x), rot(x));
}
x->push_up();
}
void access(Node *x){
for (Node *t = null; x != null; t = x, x = x->fa)
splay(x), x->c[1]=t, x->push_up();
}
Node *find_root(Node *x){
access(x); splay(x);
while (x->c[0] != null) x = x->c[0];
return x;
}
void make_root(Node *x){ access(x); splay(x); x->reverse(); }
void link(Node *x, Node *y){
if (find_root(x) == find_root(y)) return;
make_root(x); x->fa = y;
}
void cut(Node *x, Node *y){
if (x == y || find_root(x) != find_root(y)) return;
make_root(x); access(y); splay(y);
if (y->c[0] == x && x->c[1] == null){
y->c[0] = x->fa = null;
y->push_up();
}
}
void solve(Node *x, Node *y){
if (find_root(x) != find_root(y)) { puts("-1"); return; }
make_root(x); access(y); splay(y);
ll up = y->exp, down = y->sz*(y->sz+1)/2, d = __gcd(up, down);
printf("%lld/%lld\n", up/d, down/d);
}
void modify(Node *x, Node *y, ll dt){
if (find_root(x) != find_root(y)) return;
make_root(x); access(y); splay(y); y->add(dt);
}
void build(int x, int last){
if (last) loc[x]->fa = loc[last];
for (Edge *p = g[x]; p; p=p->nxt) if (p->v != last) build(p->v, x);
}
inline void addedge(int u, int v){
TAIL->v = v; TAIL->nxt = g[u]; g[u] = TAIL++;
TAIL->v = u; TAIL->nxt = g[v]; g[v] = TAIL++;
}
int main(){
setnull();
read(n); read(q);
rep(i, 1, n){ ll w; read(w); loc[i] = newNode(w); }
rep(i, 1, n-1){
int u, v; read(u); read(v);
addedge(u, v);
}
build(1, 0);
for (; q; q--){ int opt, u, v; ll d;
read(opt); read(u); read(v);
if (opt == 1) cut(loc[u], loc[v]);
else if (opt == 2) link(loc[u], loc[v]);
else if (opt == 4){ solve(loc[u], loc[v]); }
else { read(d); modify(loc[u], loc[v], d); }
}
return 0;
}