送你一颗圣诞树
2015-09-08 16:01
176 查看
题意
有mm棵树T0T_0~TmT_m,T0T_0只有一个00号节点。对于Ti(i∈[1,m])T_i(i\in[1,m]),给出ai,bi,ci,di,lia_i,b_i,c_i,d_i,l_i,表示这棵树是由TaiT_{a_i}的cic_i号节点与TbiT_{b_i}的did_i号节点间连一条长为lil_i的边构成的。在TiT_i 中,保持TaiT_{a_i} 中的所有节点编号不变,然后如果TaiT_{a_i} 中有ss 个节点,他会把TbiT_{b_i} 中的所有节点的编号加上ss。对于Ti(i∈[1,m])T_i(i\in[1,m]),求∑i=0n−1∑j=i+1n−1d[i][j]\sum\limits_{i= 0}^{n-1}\sum\limits_{j = i + 1}^{n-1}d[i][j],其中nn为TiT_i节点个数,d[i][j]d[i][j]为该树中i,ji,j的最短距离,输出modmod 109+710^9 + 7。
0≤ai,bi<i,0≤li≤1090\le a_i,b_i < i,0\le l_i\le10^9
1≤m≤601\le m\le60
数据组数T≤100T\le 100
TimeTime Limits:2000msLimits:2000ms
MemoryMemory Limits:512MLimits:512M
分析
令ans[i]ans[i]为TiT_i的答案,size[i]size[i]为TiT_i的节点个数。易得ans[i]=ans[ai]+ans[bi]+size[ai]∗size[bi]∗li+topai,ci∗size[bi]+topbi,di∗size[ai]ans[i] = ans[a_i] + ans[b_i]+size[a_i] * size[b_i] * l_i+top_{a_i,c_i} * size[b_i]+top_{b_i,d_i}*size[a_i]
topk,xtop_{k,x}表示TkT_k中所有节点到xx号节点的距离和。
现在我们看看如何求topk,xtop_{k,x}。
考虑把TkT_k分成Tak,TbkT_{a_k},T_{b_k}。
1° k=0k=0时,值为00;
2° x<size[ak]x < size[a_k]时,xx原来是在TakT_{a_k}中,那么显然topk,x=topak,x+(topbk,dk+(lk+disak,ck,x)∗size[bk])top_{k,x} = top_{a_k,x}+(top_{b_k,d_k}+(l_k+dis_{a_k,c_k,x})*size[b_k])
其中disk,x,ydis_{k,x,y}表示TkT_k中x,yx,y的距离。
3°x>=size[ak]x >= size[a_k]时,xx原来是在TbkT_{b_k}中,仿照2°,我们可以得出一个相似的方程。
这样就可以递归求解topk,xtop_{k,x}了。
我们的问题又变成了如何求disk,x,ydis_{k,x,y}。
同样考虑递归求解。
如果x,yx,y同属于组成TkT_k的两棵树中的一棵,我们可以递归下去;否则令x<yx,disk,x,y=disak,x,ck+disbk,y,dk+lkdis_{k,x,y} = dis_{a_k,x,c_k}+dis_{b_k,y,d_k}+l_k,这样变成了两个子问题,继续递归求解。边界为k=0或x=yk=0或x=y 时,disk,x,y=0dis_{k,x,y}=0。
上面top,distop,dis的求值过程可以用记忆化搜索。
求disk,x,ydis_{k,x,y}的过程最多递归mm层,时间复杂度为O(m)O(m);
求topk,x,ytop_{k,x,y}的过程最多有mm层,每层一个求disdis的过程,时间复杂度为O(m2)O(m^2)
所以总时间复杂度是O(m3)O(m^3)
代码
#include <cstdio> #include <algorithm> #include <cstring> #include <map> using namespace std; typedef long long LL; typedef pair<LL,LL> pa; const int N = 66; const LL P = 1e9 + 7; int n,a ,b ,len ; LL size ,ans ,c ,d ; map< pa , int > dis ; void init() { scanf("%d",&n); for (int i = 1;i <= n;i ++) { scanf("%d%d%lld%lld%d",&a[i],&b[i],&c[i],&d[i],&len[i]); dis[i].clear(); } } int get(int k,LL x,LL y) { if (k == 0 || x == y) return 0; if (y < x) swap(x,y); if (y < size[a[k]]) return get(a[k],x,y); if (x >= size[a[k]]) return get(b[k],x - size[a[k]],y - size[a[k]]); pa cur = make_pair(x,y); if (dis[k].find(cur) != dis[k].end()) return dis[k][cur]; int re = (0LL + get(a[k],x,c[k]) + get(b[k],y - size[a[k]],d[k]) + len[k]) % P; return dis[k][cur] = re; } int top(int k,LL x) { if (k == 0) return 0; pa cur = make_pair(x,-1); if (dis[k].find(cur) != dis[k].end()) return dis[k][cur]; int re = 0; if (x < size[a[k]]) { re = top(a[k],x); re = (re + top(b[k],d[k])) % P; re = (re + 1LL * (get(a[k],x,c[k]) + len[k]) % P * (size[b[k]] % P) % P) % P; } else { re = top(b[k],x - size[a[k]]); re = (re + top(a[k],c[k])) % P; re = (re + 1LL * size[a[k]] % P * (get(b[k],x - size[a[k]],d[k]) + len[k]) % P) % P; } return dis[k][cur] = re; } void solve() { for (int i = 1;i <= n;i ++) { int l = a[i],r = b[i]; ans[i] = (ans[l] + ans[r]) % P; size[i] = size[l] + size[r]; ans[i] = (ans[i] + size[l] % P * (size[r] % P) % P * LL(len[i]) % P) % P; ans[i] = (ans[i] + 1LL * size[l] % P * top(r,d[i]) % P) % P; ans[i] = (ans[i] + 1LL * size[r] % P * top(l,c[i]) % P) % P; printf("%lld\n",ans[i]); } } int main() { int T; scanf("%d",&T); size[0] = 1; while (T --) { init(); solve(); } }
相关文章推荐
- uva 821 floyd
- Mac monkey 尝试
- set -x与set +x指令
- Struts2国际化介绍及详细说明
- ios的单元测试
- 检测系统版本的宏
- .NET基础 (05)内存管理和垃圾回收
- 114 某种序列【大数求和】
- 树中两个节点的最低公共父节点
- C++读取XML,tinyXml的使用
- HDU2.3.1 A + B Problem II
- Makefile 连接库文件的方法
- shell脚本中位置参数 $0 $1 .. $* $#的备忘
- memmove 和 memcpy的区别
- Struts2拦截器介绍及说明
- CP-ABE的使用
- 对rtmp、NetStream.appendBytes() 使用BitmapData.draw()提示跨域问题的解决办法
- 20150908数据结构(C语言版)算法时间复杂度问题
- git diff的用法
- Android中SQLite应用详解