HDU 5575 Discover Water Tank 并查集 树形DP
题意:
有一个水槽,边界的两块板是无穷高的,中间有n-1块隔板(有高度),现有一些条件(i,y,k),表示从左到右数的第i列中,在高度为(y+0.5)的地方是否有水(有水:k = 1),问最多能同时满足多少个条件。范围:1e5
分析:
考虑按隔板的高度从小到大合并隔板相邻的两列,合并的时候新开一个节点,这个可以用并查集来做。
这样合并过来就会得到一棵树,接下来就考虑如何把询问塞进去,然后做树形DP。
对于一个询问,我们需要把它存入第i列对应的叶节点上的某个父亲那里去,这个可以用vector来做,具体是哪个父亲可以倍增地找(当然预处理的时候要求一遍lca),即高度恰好在某个隔板下,这样就可以树形DP了。
树形DP:设d[i]表示树上以节点i的子树最多能满足的条件数,f[i]表示树上以节点i为子树中节点i有水能满足的条件数,emp[i]表示树上的节点i处没有水能满足的条件数。
对于d[i],节点i处没水,就直接转移emp[i]+d[son[i][0]]+d[son[i][1]];节点i处有水,则其子树必然有水,而节点i处的条件的高度y也不是单一的,这样我们只需求一个最大的前缀和(即水淹到哪一个高度,满足的条件有多少,求一个最大值)就可以了。
对于f[i],f[son[i][0]]+f[son[i][1]]+节点i处有水的条件数。
答案为d[rt]。
-----------------------------------------------------------------------------------------------------------------------------------
另外网上的似乎有一种更容易写的方法,直接把询问建树,当然还是按列合并,算法的思路也是一致的,但是树形DP写起来很简单,就是一个递推式。
具体地说,就是把询问、隔板按高度从小到大排序,依次作为节点插入树中,若当前询问的高度,大于等于当前隔板的高度,就合并相邻两列,建一个新节点,如此建出一棵树。而DP的时候就不用特别的去求前缀和了,直接递推过来就可以。
程序:
方法1:
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <string> 5 #include <algorithm> 6 #include <iostream> 7 #include <vector> 8 9 using namespace std; 10 11 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i) 12 #define DWN(i, a, b) for (int i = (a), i##_end_ = (b); i >= i##_end_; --i) 13 #define mset(a, b) memset(a, b, sizeof(a)) 14 #define pb push_back 15 const int maxn = 2e5+10; 16 int n, m; 17 struct Node 18 { 19 int h, id; 20 bool operator < (const Node &AI) const 21 { 22 return h == AI.h ? id < AI.id : h < AI.h; 23 } 24 }a[maxn]; 25 struct Query 26 { 27 int h, ty; 28 Query(int h = 0, int ty = 0): 29 h(h), ty(ty) {} 30 bool operator < (const Query &AI) const 31 { 32 return h == AI.h ? ty < AI.ty : h < AI.h; 33 } 34 }; 35 int fa[maxn*2][20], bel[maxn*2], to[maxn][2], tip[maxn*2], bot[maxn*2], t_cnt; 36 int emp[maxn*2], f[maxn*2], d[maxn*2]; 37 vector <Query> g[maxn*2]; 38 39 template <class TAT> 40 void Ckmax(TAT &a, const TAT &b) 41 { 42 if (a < b) a = b; 43 } 44 45 int Getbel(int x) 46 { 47 return x == bel[x] ? x : bel[x] = Getbel(bel[x]); 48 } 49 50 void prepare() 51 { 52 sort(a+1, a+n); 53 REP(i, 1, n) bel[i] = tip[i] = i, bot[i] = fa[i][0] = fa[i][1] = to[i][1] = to[i][0] = 0, g[i].clear(); 54 t_cnt = n; 55 REP(i, 1, n-1) 56 { 57 int x = Getbel(a[i].id), y = Getbel(a[i].id+1); 58 t_cnt ++, g[t_cnt].clear(); 59 fa[tip[x]][0] = fa[tip[y]][0] = t_cnt; 60 bot[t_cnt] = a[i].h; 61 to[t_cnt][0] = tip[x], to[t_cnt][1] = tip[y]; 62 bel[x] = y; 63 tip[y] = t_cnt; 64 } 65 bot[0] = 0x3fffffff; 66 REP(j, 1, 19) 67 REP(i, 1, t_cnt) 68 fa[i][j] = fa[fa[i][j-1]][j-1];//, printf("%d %d : %d\n", i, j, fa[i][j]); 69 } 70 71 void work() 72 { 73 mset(d, 0), mset(f, 0); 74 REP(i, 1, t_cnt) 75 { 76 if (!g[i].empty()) 77 { 78 sort(g[i].begin(), g[i].end()); 79 int tmp, sum, sz = g[i].size(), j = 0, t_j; 80 d[i] = sum = emp[i]+((i > n) ? f[to[i][0]]+f[to[i][1]] : 0); 81 while (j < sz) 82 { 83 tmp = g[i][j].ty ? 1 : -1, t_j = j; 84 while (t_j+1 < sz && g[i][t_j+1].h == g[i][j].h) 85 t_j ++, tmp += (g[i][t_j].ty ? 1 : -1); 86 sum += tmp; 87 Ckmax(d[i], sum); 88 j = t_j+1; 89 } 90 f[i] = sum; 91 } 92 if (i > n) 93 { 94 Ckmax(d[i], emp[i]+d[to[i][0]]+d[to[i][1]]); 95 Ckmax(f[i], f[to[i][0]]+f[to[i][1]]); 96 } 97 // printf("%d %d\n", d[i], f[i]); 98 } 99 } 100 101 int main() 102 { 103 // freopen("a.in", "r", stdin); 104 // freopen("a.out", "w", stdout); 105 int T, iCase = 0; 106 scanf("%d", &T); 107 while (T --) 108 { 109 scanf("%d %d", &n, &m); 110 REP(i, 1, n-1) scanf("%d", &a[i].h), a[i].id = i; 111 prepare(); 112 mset(emp, 0); 113 REP(i, 1, m) 114 { 115 int x, h, ty; 116 scanf("%d %d %d", &x, &h, &ty); 117 DWN(j, 19, 0) 118 if (bot[fa[x][j]] <= h) x = fa[x][j]; 119 g[x].pb(Query(h, ty)); 120 emp[x] += (ty == 0); 121 } 122 work(); 123 printf("Case #%d: %d\n", ++iCase, d[t_cnt]); 124 } 125 return 0; 126 }
View Code
方法2:
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <string> 5 #include <algorithm> 6 #include <iostream> 7 #include <vector> 8 9 using namespace std; 10 11 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i) 12 #define mset(a, b) memset(a, b, sizeof(a)) 13 #define max_(a, b) a > b ? a : b 14 #define pb push_back 15 16 const int maxn = 2e5+10; 17 int n, m; 18 struct Node 19 { 20 int h, id; 21 Node (int h = 0, int id = 0): 22 h(h), id(id) {} 23 bool operator < (const Node &AI) const 24 { 25 return h == AI.h ? id < AI.id : h < AI.h; 26 } 27 }a[maxn]; 28 struct Query 29 { 30 int x, y, z; 31 void read(){ scanf("%d %d %d", &x, &y, &z); } 32 bool operator < (const Query &AI) const 33 { 34 return y == AI.y ? x < AI.x : y < AI.y; 35 } 36 }b[maxn]; 37 int f[maxn], g[maxn], dp[maxn*4][2]; 38 vector <int> e[maxn*4]; 39 40 int find_fa(int x) { return f[x] == x ? x : f[x] = find_fa(f[x]); } 41 42 void dfs(int x) 43 { 44 for (int i = 0, siz = e[x].size(); i < siz; ++i) 45 { 46 int y = e[x][i]; 47 dfs(y); 48 dp[x][0] += max_(dp[y][1], dp[y][0]); 49 dp[x][1] += dp[y][1]; 50 } 51 } 52 53 int main() 54 { 55 // freopen("a.in", "r", stdin); 56 // freopen("a.out", "w", stdout); 57 int T, iCase = 0; 58 scanf("%d", &T); 59 while (T --) 60 { 61 scanf("%d %d", &n, &m); 62 REP(i, 1, n-1) scanf("%d", &a[i].h), a[i].id = i; 63 REP(i, 1, m) b[i].read(); 64 REP(i, 1, n) 65 { 66 f[i] = g[i] = i; 67 e[i].clear(), dp[i][0] = dp[i][1] = 0; 68 } 69 sort(a+1, a+n), sort(b+1, b+m+1); 70 int now = n, cnt_n = 1, cnt_m = 1; 71 while (cnt_m <= m || cnt_n < n) 72 { 73 if (cnt_m == m+1 || cnt_n < n && a[cnt_n].h <= b[cnt_m].y) 74 { 75 int x = find_fa(a[cnt_n].id), y = find_fa(a[cnt_n].id+1); 76 e[++now].clear(), dp[now][0] = dp[now][1] = 0; 77 e[now].pb(g[x]), e[now].pb(g[y]); 78 f[x] = y, g[y] = now; 79 cnt_n ++; 80 } 81 else 82 { 83 int x = find_fa(b[cnt_m].x); 84 if (b[cnt_m-1].y == b[cnt_m].y && find_fa(b[cnt_m-1].x) == x) 85 dp[g[x]][b[cnt_m].z] ++; 86 else 87 { 88 e[++now].clear(), dp[now][0] = dp[now][1] = 0; 89 e[now].pb(g[x]); 90 g[x] = now; 91 dp[now][b[cnt_m].z] ++; 92 } 93 cnt_m ++; 94 } 95 } 96 dfs(now); 97 printf("Case #%d: %d\n", ++iCase, max_(dp[now][0], dp[now][1])); 98 } 99 return 0; 100 }
View Code
转载于:https://www.cnblogs.com/-ZZB-/p/6585867.html
HDU 5575 Discover Water Tank 并查集 树形DP相关推荐
- HDU 5575 Discover Water Tank 并查集+左偏树
不妨假定初始答案为所有的无水询问,因为这样一定没有冲突. 然后枚举有水询问.水位线到这里时,答案能否更优. 若水位线达到某一高度,则可能淹没旁边的水箱,那么实际就变成了一个大水箱,所以考虑用并查集来优 ...
- HDU 5575 Discover Water Tank(线段树+自底向上dp+并查集)
题意 给定n个挡板和m次回答,每次回答为x号水池的H+0.5高度是否有水,问这些回答互不矛盾的最大集合. 题解 设定状态dp[i][0-1]代表第i个区间枚举到当前回答后有水的最大不矛盾集合和没水的最 ...
- hdu 5575 Discover Water Tank(可合并堆)
题目链接:hdu 5575 Discover Water Tank 题意: 有一个大水箱,里面有N-1个隔板,将这个大水箱分成了N个小水箱,每个隔板有一定的高度. 现在有m条信息,每条信息表示第x个水 ...
- hdu 5575 Discover Water Tank 左偏树
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5575 题意: 现在有一个巨大的水库(可视为二维的),水库中间被 n−1n-1n−1 个挡板分成了 n ...
- HDU 5575 Discover Water Tank
原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=5575 把每个水箱当作一个并查集,每个无水的探测当做一个左偏树.有水的探测则放在数组中.并用一个数组使水 ...
- HDU 5575 Discover Water Tank(左偏树)
https://vjudge.net/problem/HDU-5575 题意: 有一个水箱,被n-1块板子分成了n个部分,板子的高度不尽相同.现在有m次探测,每次探测在第x部分的y+0.5高度处是否有 ...
- 图论500题 ---- 并查集+树形dp+枚举 求解动态的最小生成树 HDU 4126
题目链接 题目大意: 给一图,n个点,m条边,每条边有个花费,给出q条可疑的边,每条边有新的花费,每条可疑的边出现的概率相同,求不能经过原来可疑边(可以经过可疑边新的花费构建的边),注意每次只出现一条 ...
- HDU5575 Discover Water Tank 2015上海现场赛D题 (树形dp,并查集,左偏树)
题目大意: 有一个1维的长度为N,高度无限的水柜,现在要用N-1个挡板将其分为N个长度为1的小格,然后向水柜中注水,水可以低于挡板也可以以溢出去(这样就要与旁边格子的水位相同),现在有M次探测,探测i ...
- 树形DP+并查集+左偏树, HDU-5575,Discover Water Tank,2015上海现场赛D题
只是ACM/IICPC 2015 上海区域赛的一道题.原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=5575 题目描述 N-1个木板把一个水箱划分成了N ...
最新文章
- 高通将用芯片改变无人机行业格局
- office 2013 安装问题
- 八十三、经典排序算法之堆排序
- BZOJ 4517 组合数+错排
- c++获取macos中的uuid的两种方式
- php 生成器 封装,php生成器
- windows 快捷调用
- sql server中case的简单示例
- 制作png格式透明图片的简易方法
- 一篇散文简单的了解Redis
- 计算机cpu intel,intel CPU后面带F是什么意思?Intel处理器后面带“F”含义详解
- Android群英传 笔记1 安卓 系统架构和开发工具
- python找房源_python抓取链家房源信息(三)
- MacOS / Vmware Fusion无法连接虚拟设备sata0:1,因为主机上没有相应设备
- java esc_java里控制台按esc键退出,怎么实现
- 如何使用Graylog来收集日志?
- JsonFormat使用经历
- Robin六种常用负载均衡算法源码解析
- 如何做医美直播?从直播的这三个阶段出发
- A+成绩入选纳斯达克100指数 中国版DocuSign何时诞生?