LG P5138 fibonacci Solution
Description
给你一棵以 111 为根的树 TTT,点有点权 wiw_iwi,初始为 000。
设 dep(u)\operatorname{dep}(u)dep(u) 为 uuu 的深度(不带权),fib(n)\operatorname{fib}(n)fib(n) 为斐波那契数列第 nnn 项(nnn 可为负数)。
执行 qqq 次操作,操作分两种:
U x k
:对每个 u∈subtree(x)u\in \operatorname{subtree}(x)u∈subtree(x) 执行 wu←wu+fib(dep(u)−dep(x)+k)w_u\gets w_u + \operatorname{fib}(\operatorname{dep}(u)-\operatorname{dep}(x)+k)wu←wu+fib(dep(u)−dep(x)+k)。Q x y
:查询链 x→yx\to yx→y 上的点权和,对 (109+7)(10^9+7)(109+7) 取模。
Limitations
1≤n,q≤1051\le n,q\le 10^51≤n,q≤105
1≤u,v≤n1\le u,v\le n1≤u,v≤n
1≤k≤1081\le k\le 10^81≤k≤108
1s,125MB1\text{s},125\text{MB}1s,125MB
Solution
根据 fib\operatorname{fib}fib 的性质,有:
fib(n+m)=fib(n−1)×fib(m)+fib(n)×fib(m+1)\operatorname{fib}(n+m)=\operatorname{fib}(n-1)\times\operatorname{fib}(m)+\operatorname{fib}(n)\times\operatorname{fib}(m+1)fib(n+m)=fib(n−1)×fib(m)+fib(n)×fib(m+1)
所以对于每次 U
操作,点 uuu 增加的值为:
fib(dep(u)−1)×fib(k−dep(x))+fib(dep(u))×fib(k−dep(x)+1)\operatorname{fib}(\operatorname{dep}(u)-1)\times\operatorname{fib}(k-\operatorname{dep}(x))+\operatorname{fib}(\operatorname{dep}(u))\times\operatorname{fib}(k-\operatorname{dep}(x)+1)fib(dep(u)−1)×fib(k−dep(x))+fib(dep(u))×fib(k−dep(x)+1)
那么每个点的权值就可以写成 fib(dep(u)−1)×p+fib(dep(u))×q\operatorname{fib}(\operatorname{dep}(u)-1)\times p+\operatorname{fib}(\operatorname{dep}(u))\times qfib(dep(u)−1)×p+fib(dep(u))×q 的形式,用线段树维护 p,qp,qp,q 和答案即可。
查询时直接用树剖,求 fib(n)\operatorname{fib}(n)fib(n) 可以用矩阵或扩域,处于常数考虑可以选择后者。
那么就做完了,时间复杂度 O(qlog2nlogV)O(q\log^2 n\log V)O(qlog2nlogV)。
Code
粘了一堆板子,所以省略了一部分,代码中的深度从 000 开始。
#include <bits/stdc++.h>
using namespace std;using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;template<class T>
bool chmax(T &a, const T &b){if(a < b){ a = b; return true; }return false;
}template<class T>
bool chmin(T &a, const T &b){if(a > b){ a = b; return true; }return false;
}template <int MOD>
struct modint {};
using Z = modint<1000000007>;template<int S>
struct quad {};using Q5 = quad<5>;
const Z half = Z(2).inv();template<class T>
Z fib(T n) {if (n == 0) return 0;Q5 phi = Q5(half, half), psi = Q5(half, -half), sqrt5 = Q5(0, 1);if (n > 0) return ((phi.pow(n) - psi.pow(n)) / sqrt5).value();else {Z res = ((phi.pow(-n) - psi.pow(-n)) / sqrt5).value();return ((-n) & 1) ? res : -res;}
}template<class Info, class Tag>
struct lazy_segment{};struct tag {Z a, b;inline tag() : tag(0, 0) {}inline tag(Z a, Z b) : a(a), b(b) {}inline void apply(const tag& t) { a += t.a, b += t.b; }
};struct info {Z a, b, sum;inline info() {}inline info(Z a, Z b, Z sum) : a(a), b(b), sum(sum) {}inline void apply(const tag& t) { sum += t.a * a + t.b * b; }inline info operator+(const info& rhs) const {return {a + rhs.a, b + rhs.b, sum + rhs.sum};}
};signed main() {ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n, q;cin >> n >> q;vector<vector<int>> g(n);for (int i = 0, u, v; i < n - 1; i++) {cin >> u >> v, u--, v--;g[u].push_back(v);g[v].push_back(u);}vector<int> dep(n), par(n), siz(n), son(n, -1);auto dfs = [&](auto&& self, int u, int fa) -> void {siz[u] = 1, par[u] = fa;for (auto v : g[u]) {if (v == fa) continue;dep[v] = dep[u] + 1;self(self, v, u);siz[u] += siz[v];if (son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v;}};int clock = 0;vector<int> dfn(n), top(n);vector<info> seq(n);auto dfs2 = [&](auto&& self, int u, int topf) -> void {seq[dfn[u] = clock++] = {fib(dep[u]), fib(dep[u] + 1), 0};top[u] = topf;if (~son[u]) self(self, son[u], topf);for (auto v : g[u]) {if (v == par[u] || v == son[u]) continue;self(self, v, v);}};dfs(dfs, 0, 0);dfs2(dfs2, 0, 0);lazy_segment<info, tag> tree(seq);auto ask = [&](int u, int v) {Z res = 0;while (top[u] != top[v]) {if (dep[top[u]] < dep[top[v]]) swap(u, v);res += tree.query(dfn[top[u]], dfn[u]).sum;u = par[top[u]];}if (dfn[u] > dfn[v]) swap(u, v);res += tree.query(dfn[u], dfn[v]).sum; return res;};auto upd = [&](int u, i64 k) {tree.apply(dfn[u], dfn[u] + siz[u] - 1,{fib(k - dep[u] - 1), fib(k - dep[u])}); };for (int i = 0; i < q; i++) {char op; cin >> op;if (op == 'U') {int u; i64 k;cin >> u >> k, u--;upd(u, k);}else {int u, v;cin >> u >> v, u--, v--;cout << ask(u, v) << '\n';}}return 0;
}