[贪心+DFS序列维护树上前缀和]2014 Multi-University Training Contest 5 - 1002 Paths on the tree
来源:互联网 发布:windows 7模拟器手机版 编辑:程序博客网 时间:2024/06/06 18:17
题目链接: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表示路径不存在取过路径的子树
代码:
#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[N];int n, m, tot, tim;int adj[N], next[2*N], aim[2*N], dep[N], fa[N];int anc[N][21], st[N], en[N], c[N];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;
0 0
- [贪心+DFS序列维护树上前缀和]2014 Multi-University Training Contest 5 - 1002 Paths on the tree
- 【HDU5743 2016 Multi-University Training Contest 2J】【dfs展开式DP 前缀和思想】Join The Future 40个数已知区间和为奇或偶输出方案
- 2014多校5---1002 HDU4912 ( Paths on the tree ) LCA+贪心+bfs/dfs
- 2014 Multi-University Training Contest 8 1002
- 2016 Multi-University Training Contest 5 1003 Divide the Sequence (贪心)
- 2014 Multi-University Training Contest 1/HDU4864_Task(贪心)
- 2014 Multi-University Training Contest 6 Apple Tree(数学题)
- hdu 4925 Apple Tree--2014 Multi-University Training Contest 6
- hdu 4925 Apple Tree 2014 Multi-University Training Contest 6
- HDU 4912(Paths on the tree-树上取链,贪心)
- hdu4869 Turn the pokers 2014 Multi-University Training Contest 1
- 【2014 Multi-University Training Contest 3】 The Great Pan
- hdu4891 The Great Pan 2014 Multi-University Training Contest 3
- hdu4901 The Romantic Hero 2014 Multi-University Training Contest 4
- 2014 Multi-University Training Contest 6 Fighting the Landlords
- 2012 Multi-University Training Contest 5:Mark the Rope
- 2016 多校 Multi-University Training Contest 5 Divide the Sequence
- 2016 Multi-University Training Contest 5 1003 Divide the Sequence
- 定时器的使用
- 矩阵快速幂 小讲
- ZOJ-1208
- lightoj 1005
- [水]ZOJ1392
- [贪心+DFS序列维护树上前缀和]2014 Multi-University Training Contest 5 - 1002 Paths on the tree
- 二进制输入输出流接口设计(C++)
- java开发中的那些事(6)------一次ajax调用中的问题
- session_id()
- 【LeetCode】Two Sum——第一次接触LeetCode
- hibernate.properties 各种配置
- lihgtoj 1006
- lucene 4.x 近实时搜索
- Oracle中创建视图