您的位置:首页 > 其它

[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: