点分治 nbut1654 Ancient battle tree
2016-02-12 17:24
344 查看
传送门:点击打开链接
题意:一棵树,求点对数,满足两点之间的最短距离等于树的最长链长。
思路:比较蠢,只想到点分治。
先用DFS求出树的最长链,然后跑点分治,这题很类似楼教主的男人八题的那题,不过那个更复杂些。
还有一个trick,就是如果n=1,只有1个点,那么最长链长等于0,满足的题意的点对有(0,0),所以应该输出1,这里需要特判一下
题意:一棵树,求点对数,满足两点之间的最短距离等于树的最长链长。
思路:比较蠢,只想到点分治。
先用DFS求出树的最长链,然后跑点分治,这题很类似楼教主的男人八题的那题,不过那个更复杂些。
还有一个trick,就是如果n=1,只有1个点,那么最长链长等于0,满足的题意的点对有(0,0),所以应该输出1,这里需要特判一下
#include<map> #include<set> #include<cmath> #include<ctime> #include<stack> #include<queue> #include<cstdio> #include<cctype> #include<string> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #include<functional> #define fuck(x) cout<<"["<<x<<"]" #define FIN freopen("input.txt","r",stdin) #define FOUT freopen("output.txt","w+",stdout) using namespace std; typedef long long LL; const int MX = 4e4 + 5; const int MS = 4e4 + 5; const int INF = 0x3f3f3f3f; struct Edge { int v, nxt, cost; } E[MS]; int rear, Head[MX]; void edge_init() { rear = 0; memset(Head, -1, sizeof(Head)); } void edge_add(int u, int v, int cost) { E[rear].v = v; E[rear].cost = cost; E[rear].nxt = Head[u]; Head[u] = rear++; } int vis[MX], A[MX], cnt[MX]; int Tree_cnt(int u, int f) { int ret = 1; for(int i = Head[u]; ~i; i = E[i].nxt) { int v = E[i].v; if(v == f || vis[v]) continue; ret += Tree_cnt(v, u); } return ret; } int G_DFS(int n, int u, int f, int &ansn, int &ansid) { A[u] = 1; int ret = 0; for(int i = Head[u]; ~i; i = E[i].nxt) { int v = E[i].v; if(v == f || vis[v]) continue; int nxt = G_DFS(n, v, u, ansn, ansid); ret = max(ret, nxt); A[u] += ret; } ret = max(ret, n - A[u]); if(ret < ansn) ansn = ret, ansid = u; return A[u]; } int Tree_G(int u) { int cnt = Tree_cnt(u, -1), ansn = INF, ansid = 0; G_DFS(cnt, u, -1, ansn, ansid); return ansid; } void Tree_deep(int u, int f, int d, int &DFN) { A[++DFN] = d; for(int i = Head[u]; ~i; i = E[i].nxt) { int v = E[i].v, cost = E[i].cost; if(v == f || vis[v]) continue; Tree_deep(v, u, d + cost, DFN); } } LL F_deal(int u, int k) { if(k <= 0) return 0; int DFN = 0; LL ans = 0; for(int i = Head[u]; ~i; i = E[i].nxt) { int v = E[i].v, cost = E[i].cost; if(vis[v]) continue; Tree_deep(v, u, cost, DFN); } for(int i = 1; i <= DFN; i++) cnt[i] = 0; for(int i = 1; i <= DFN; i++) cnt[A[i]]++; if(k <= DFN) ans += cnt[k]; for(int i = 1; i < (k + 1) / 2; i++) { if(i <= DFN && k - i <= DFN) ans += (LL)cnt[i] * cnt[k - i]; } if(k % 2 == 0 && k / 2 <= DFN) ans += (LL)cnt[k / 2] * (cnt[k / 2] - 1) / 2; return ans; } LL solve(int u, int k) { int g = Tree_G(u); vis[g] = 1; LL ans = F_deal(g, k); for(int i = Head[g]; ~i; i = E[i].nxt) { int v = E[i].v, cost = E[i].cost; if(vis[v]) continue; ans -= F_deal(v, k - 2 * cost); ans += solve(v, k); } return ans; } int solve_line(int u, int from, int &ans) { int Max1 = 0, Max2 = 0; for(int id = Head[u]; ~id; id = E[id].nxt) { int v = E[id].v; if(v == from) continue; int t = solve_line(v, u, ans) + 1; if(t > Max1) { Max2 = Max1; Max1 = t; } else if(t > Max2) Max2 = t; } ans = max(ans, Max1 + Max2); return Max1; } int main() { int n; while(~scanf("%d", &n)) { edge_init(); memset(vis, 0, sizeof(vis)); if(n == 1) { printf("1\n"); continue; } for(int i = 1; i <= n - 1; i++) { int u, v, cost; scanf("%d%d", &u, &v); edge_add(u, v, 1); edge_add(v, u, 1); } int line = 0; solve_line(1, -1, line); printf("%I64d\n", solve(1, line)); } return 0; }
相关文章推荐
- NGUI 3.5教程(二)Label 标签 (Hello world)、多行文本
- poj--2516--Minimum Cost(最小费用流)
- Android Studio API23以后HttpClient
- 不抛出异常的swap
- 浅谈程序的性格
- Android Wear开启通过蓝牙调试后,显示"主机:已断开连接"解决方法
- Notepad++直接编译运行Java
- NYOJ-组合数
- tomcat-闪退和启动两个tomcat解决方法
- 设计模式(四)简单工厂模式
- 设计模式(四)简单工厂模式
- 设计模式之简单工厂模式
- Oracle Restart可以用来给Oracle GoldenGate 做 High Availability 使用么?
- 迭代器
- 后缀平衡树 nbut1653 String in the tree
- ElasticSearch初步学习,创建索引(入门一)
- python中List添加元素的几种方法
- hdu--2089(打表)
- 类装载器读取properties资源文件
- macbook安装mysql