[51Nod算法马拉松14 F] 斐波那契树
2016-05-30 10:03
253 查看
官方题解用树上倍增做的…转移感觉超级厉害也超级麻烦我没有看懂 QAQ 所以来分享一下点分 + 矩阵的做法… 分治跟 SCOI 2016 D1T2 其实挺像的就不多说了 有什么细节问题可以看代码
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <bitset> #include <cmath> #include <ctime> #include <algorithm> #include <iterator> #include <vector> #include <queue> #include <set> #include <map> #define rep(i, x, y) for (int i = (x), _ = (y); i <= _; ++i) #define down(i, x, y) for (int i = (x), _ = (y); i >= _; --i) #define x first #define y second using namespace std; typedef long long LL; template<typename T> inline void upMax(T & x, T y) { x < y ? x = y : 0; } template<typename T> inline void upMin(T & x, T y) { x > y ? x = y : 0; } template<typename T> inline void read(T & x) { char c; while ((c = getchar()) < '0' || c > '9') ; for (x = c - '0'; (c = getchar()) >= '0' && c <= '9'; x = x * 10 + c - '0') ; } const int inf = 0x3f3f3f3f; const int mo = 1e9 + 9; const int N = 1e5 + 10; inline int inc(int x, int y) { return (x += y) >= mo ? x - mo : x; } inline int dec(int x, int y) { return (x -= y) < 0 ? x + mo : x; } struct matrix { LL e[2][2]; inline void set(int f) { memset(e, 0, sizeof(e)); e[0][0] = e[1][1] = f; } inline matrix operator + (const matrix & b) const { static matrix ret; rep (i, 0, 1) rep (j, 0, 1) (ret.e[i][j] = e[i][j] + b.e[i][j]) >= mo ? ret.e[i][j] -= mo : 0; return ret; } inline matrix operator - (const matrix & b) const { static matrix ret; rep (i, 0, 1) rep (j, 0, 1) (ret.e[i][j] = e[i][j] - b.e[i][j]) < 0 ? ret.e[i][j] += mo : 0; return ret; } inline matrix operator * (const matrix & b) const { static matrix ret; rep (i, 0, 1) rep (j, 0, 1) ret.e[i][j] = (e[i][0] * b.e[0][j] + e[i][1] * b.e[1][j]) % mo; return ret; } inline matrix operator * (const int b) const { static matrix ret; rep (i, 0, 1) rep (j, 0, 1) ret.e[i][j] = e[i][j] * b % mo; return ret; } }; matrix fib ; struct edge { int to; edge *n; }; struct Data { int x, y, id, v; inline bool operator < (const Data & b) const { return v < b.v; } } qus ; int Ans ; namespace myTree { edge poolEdge[N * 2], *cur = poolEdge, *head ; inline void addEdge(int x, int y) { cur->to = y, cur->n = head[x], head[x] = cur++; cur->to = x, cur->n = head[y], head[y] = cur++; } int pSize , TOT; void initDfs(int x, int fa) { pSize[x] = 1; for (edge *p = head[x]; p; p = p->n) if (p->to != fa) { initDfs(p->to, x); pSize[x] += pSize[p->to]; } } inline int getSize(int x, int y) { return pSize[x] > pSize[y] ? pSize[y] : TOT - pSize[x]; } bool del ; int nodeTot, center, cVal; int size ; void calcRoot(int x, int fa) { int mx = 0; size[x] = 1; for (edge *p = head[x]; p; p = p->n) { int to = p->to; if (del[to] || to == fa) continue ; calcRoot(to, x); size[x] += size[to]; upMax(mx, size[to]); } upMax(mx, nodeTot - size[x]); if (mx < cVal) center = x, cVal = mx; } matrix f , h ; LL g , num ; int deep , top , col , tim; void calc_1(int x, int fa) { col[x] = tim; g[x] = 0; num[x] = 1; for (edge *p = head[x]; p; p = p->n) { int to = p->to; if (to == fa) continue ; if (del[to]) { int tmp = getSize(x, to); g[x] = inc(g[x], num[x] * tmp % mo); num[x] += tmp; continue ; } else { top[to] = top[x]; calc_1(to, x); g[x] = inc(g[x], num[x] * num[to] % mo); num[x] += num[to]; } } } void calc_2(int x, int fa) { for (edge *p = head[x]; p; p = p->n) { int to = p->to; if (del[to] || to == fa) continue ; g[to] = inc(g[to], dec(g[x], (h[x].e[0][0] + num[x] - num[to]) * num[to] % mo)); h[to] = h[x] * fib[1] + fib[1] * (num[x] - num[to]); g[to] = inc(g[to], (h[to] * num[to]).e[0][0]); f[to] = f[x] + (fib[deep[x] + 1] - fib[deep[x]]) * num[to]; deep[to] = deep[x] + 1; calc_2(to, x); } } int work(int root, int l, int r) { deep[root] = 0; num[root] = 1, g[root] = 0; for (edge *p = head[root]; p; p = p->n) { if (!del[p->to]) { ++tim; top[p->to] = p->to; calc_1(p->to, root); g[root] = inc(g[root], num[root] * num[p->to] % mo); num[root] += num[p->to]; } else { int tmp = getSize(root, p->to); g[root] = inc(g[root], num[root] * tmp % mo); num[root] += tmp; } } for (edge *p = head[root]; p; p = p->n) if (!del[p->to]) { deep[p->to] = 1; f[p->to] = fib[1] * num[p->to]; h[p->to].set(0); calc_2(p->to, root); } for (int i = l; i <= r; ++i) { int x = qus[i].x, y = qus[i].y; if (deep[x] > deep[y]) swap(x, y); if (x == root) { if (y == root) Ans[qus[i].id] = g[root]; else { int tmp1 = f[y].e[0][0] * (num[root] - num[top[y]]) % mo; int tmp2 = (g[y] + g[root] - (num[root] - num[top[y]]) * num[top[y]] % mo + mo) % mo; Ans[qus[i].id] = inc(tmp1, tmp2); } } else if (col[x] == col[y]) { qus[i].v = col[x]; swap(qus[i--], qus[r--]); } else { int tmp1 = dec(g[root], ((num[root] - num[top[x]]) * num[top[x]] + (num[root] - num[top[x]] - num[top[y]]) * num[top[y]]) % mo); int tmp2 = inc((f[x] * f[y]).e[0][0], (f[x] + f[y]).e[0][0] * (num[root] - num[top[x]] - num[top[y]]) % mo); int tmp3 = inc(g[x], g[y]); Ans[qus[i].id] = inc(inc(tmp1, tmp2), tmp3); } } return r; } void Dfs(int x, int tot, int l, int r) { del[x] = 1; l = work(x, l, r) + 1; sort(qus + l, qus + r + 1); for (edge *p = head[x]; p; p = p->n) { int to = p->to; if (del[to]) continue ; nodeTot = cVal = size[to] < size[x] ? size[to] : tot - size[x]; calcRoot(to, 0); int cur = l; while (qus[l].v == col[to]) ++l; if (cur == l) continue ; Dfs(center, size[to], cur, l - 1); } } void build(int n, int Q) { cVal = nodeTot = n; calcRoot(1, 0); Dfs(center, n, 1, Q); } } int main() { #ifdef LX_JUDGE freopen("in.txt", "r", stdin); #endif int n, Q; read(n); myTree::TOT = n; fib[0].set(1); fib[1].e[0][0] = 1, fib[1].e[0][1] = 1; fib[1].e[1][0] = 1, fib[1].e[1][1] = 0; rep (i, 2, n) fib[i] = fib[i - 1] * fib[1]; for (int i = 1, x, y; i < n; ++i) { read(x), read(y); myTree::addEdge(x, y); } read(Q); rep (i, 1, Q) { read(qus[i].x), read(qus[i].y); qus[i].id = i; } myTree::initDfs(1, 0); myTree::build(n, Q); rep (i, 1, Q) printf("%d\n", Ans[i]); return 0; }
相关文章推荐
- Struts2开发基本步骤
- 快排,二分查找
- LINUX连接mysql数据库
- JavaScript学习--Item13 理解 prototype, getPrototypeOf 和__proto__
- Hibernate配置文件详解
- c 网络字节序和本机字节序转换
- systemctl使用说明
- php求圆周率的简单实现方法[原创]_php技巧_脚本之家
- 值得分享的轻量级Bootstrap Table表格插件
- 定制Eclipse IDE之杂症篇
- 深入理解React、Redux
- oracle11g的standby性能分析报告statpack安装
- IE 6浏览器不支持 a:hover
- Javascript 检查字符串是否是数字的几种方法
- 心灵鸡汤
- 定制Eclipse IDE之插件篇(二)
- js获取所有checkbox的值的简单实例
- iOS-TWRProgressView
- ABAP SORT
- Android 拍照或从相册取图片并裁剪