[贪心+DFS序列维护树上前缀和]2014 Multi-University Training Contest 5 - 1002 Paths on the tree
2014-08-07 00:23
549 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4912
题目大意:给定一颗树和树上的m条路径,询问最多取多少两两不相交的路径
思路:若两路径相交,一定存在公共的LCA,比赛时考虑匹配,DP之类的思路,没有结果,官方解法是很巧妙的贪心:
把所有路径的LCA按深度从大到小排序,按这个顺序取所有互不相交的路径数就是答案。
若取了一条路径,则过与这条路径共LCA的路径都不能取。
按深度从大往小取,可以保证之前放好的路径不会影响到后面的路径,且每次留给后面的路径数最多。
具体实现先按LCA的深度排序,取路径时树状数组维护DFS序列。
若取一条路径,把DFS序中LCA所在的st[i]维护+1,出了LCA的节点en[i]+1维护-1,表示LCA所在的子树已经不能取路径(深度比该LCA大的路径已经取完,深度比LCA小的路径不能经过这颗子树)
判断能否取一条路径,计算路径两端点到LCA的前缀和是否为0(sum(st[A / B])- sum(st[ father[LCA] ])),为0表示路径不存在取过路径的子树
代码:
Tips :
题目大意:给定一颗树和树上的m条路径,询问最多取多少两两不相交的路径
思路:若两路径相交,一定存在公共的LCA,比赛时考虑匹配,DP之类的思路,没有结果,官方解法是很巧妙的贪心:
把所有路径的LCA按深度从大到小排序,按这个顺序取所有互不相交的路径数就是答案。
若取了一条路径,则过与这条路径共LCA的路径都不能取。
按深度从大往小取,可以保证之前放好的路径不会影响到后面的路径,且每次留给后面的路径数最多。
具体实现先按LCA的深度排序,取路径时树状数组维护DFS序列。
若取一条路径,把DFS序中LCA所在的st[i]维护+1,出了LCA的节点en[i]+1维护-1,表示LCA所在的子树已经不能取路径(深度比该LCA大的路径已经取完,深度比LCA小的路径不能经过这颗子树)
判断能否取一条路径,计算路径两端点到LCA的前缀和是否为0(sum(st[A / B])- sum(st[ father[LCA] ])),为0表示路径不存在取过路径的子树
代码:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define foru(i, a, b) for(int i=(a); i<=(b); i++) #define ford(i, a, b) for(int i=(a); i>=(b); i--) #define clr(a, b) memset(a, (b), sizeof(a)) typedef long long ll; const double Pi = 4 * atan(1.0); inline int readint() { char c = getchar(); while(!isdigit(c)) c = getchar(); int ret = 0; while(isdigit(c)) ret = ret * 10 + c - '0', c = getchar(); return ret; } /*************************************************************/ const int N = 100010; struct Edge{ int a, b; int lca; }E ; int n, m, tot, tim; int adj , next[2*N], aim[2*N], dep , fa ; int anc [21], st , en , c ; void add(int a, int b){ tot ++; aim[tot] = b; next[tot] = adj[a]; adj[a] = tot; } void init(){ tot = 0; clr(adj, 0); foru(i, 1, n-1){ int u = readint(); int v = readint(); add(u, v); add(v, u); } foru(i, 1, m) { E[i].a = readint(); E[i].b = readint(); } } void dfs(int x, int pre){ st[x] = ++tim; dep[x] = dep[pre] + 1; fa[x] = anc[x][0] = pre; int k = adj[x]; while (k){ int tx = aim[k]; if (tx != pre) dfs(tx, x); k = next[k]; } en[x] = tim; } int swim(int x, int H){ for(int i = 0; H; i++){ if (1&H) x = anc[x][i]; H >>= 1; } return x; } int LCA(int x, int y){ if (dep[x] < dep[y]) swap(x, y); x = swim(x, dep[x] - dep[y]); if (x == y) return x; ford(i, 20, 0) if (anc[x][i] != anc[y][i]){ x = anc[x][i]; y = anc[y][i]; } return anc[x][0]; } bool cmp(Edge x, Edge y){ return dep[x.lca] > dep[y.lca]; } void prepare(){ tim = dep[1] = 0; dfs(1, 1); fa[1] = 0; foru(j, 1, 20) foru(i, 1, n) anc[i][j] = anc[anc[i][j-1]][j-1]; foru(i, 1, m) E[i].lca = LCA(E[i].a, E[i].b); sort(E+1, E+1+m, cmp); } int lowbit(int x){ return x&(-x); } void modify(int k, int x){ while (k < n){ c[k] += x; k += lowbit(k); } } int sum(int k){ int s = 0; while (k > 0){ s += c[k]; k -= lowbit(k); } return s; } int ans; void solve(){ ans = 0; clr(c, 0); foru(i, 1, m){ int a = E[i].a; int b = E[i].b; int lca = E[i].lca; if (sum(st[a]) - sum(st[fa[lca]]) != 0) continue; // ? fa[lca] if (sum(st[b]) - sum(st[fa[lca]]) != 0) continue; ans ++; modify(st[lca], 1); modify(en[lca]+1, -1); } printf("%d\n", ans); } int main(){ freopen("1002.txt", "r", stdin); while (scanf("%d %d", &n, &m) != EOF){ init(); prepare(); solve(); } return 0; }
Tips :
DSF序列+树状数组可维护某节点到根的前缀和 -> 子树的st[i]维护+1,en[i]+1维护-1;
相关文章推荐
- 【HDU5743 2016 Multi-University Training Contest 2J】【dfs展开式DP 前缀和思想】Join The Future 40个数已知区间和为奇或偶输出方案
- 【2014 Multi-University Training Contest 3 1002】/【HDU 4888】 Redraw Beautiful Drawings
- hdu4901 The Romantic Hero 2014 Multi-University Training Contest 4
- 【动态规划】【2014 Multi-University Training Contest 4】The Romantic Hero
- 【HDU 2014 Multi-University Training Contest 1 1002】/【HDU 4862】Jump
- hdu 4901 The Romantic Hero 2014 Multi-University Training Contest 4 E
- 【贪心】【2014 Multi-University Training Contest 2】1011 ZCC Loves Codefires
- 【阅读理解】【2014 Multi-University Training Contest 3】The Great Pan
- HDU 4898 The Revenge of the Princess’ Knight ( 2014 Multi-University Training Contest 4 )
- 【2014 Multi-University Training Contest 6】 J. Fighting the Landlords(模拟)
- 【2014 Multi-University Training Contest 3】 The Great Pan
- hdu 4891 The Great Pan---2014 Multi-University Training Contest 3
- hdu4869 Turn the pokers 2014 Multi-University Training Contest 1
- hdu 4967 Handling the Past 线段树 2014 Multi-University Training Contest 9-1008
- HDU 4869 Turn the pokers (2014 Multi-University Training Contest 1)
- HDU 4898 The Revenge of the Princess’ Knight ( 2014 Multi-University Training Contest 4 )
- hdu4891 The Great Pan 2014 Multi-University Training Contest 3
- 【2014 Multi-University Training Contest 3 1002】/【HDU 4888】 Redraw Beautiful Drawings
- 2014 Multi-University Training Contest 6 Fighting the Landlords
- hdu 4869 Turn the pokers 2014 Multi-University Training Contest 1