只是ACM/IICPC 2015 上海区域赛的一道题。原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=5575

题目描述

N-1个木板把一个水箱划分成了N部分(从左到右形成了编号为[1,N]的N个小水箱)。这些木板高度不尽相同。因为水往低处流和木板相隔,所以整个大水箱中有若干个高低不同的水平面。

接下来进行M次探测,探测指定地方指定高度有没有水。这些探测中包含错误结果,求 可能的正确探测数目的最大值。

输入

T组数据。
每组数据以N和M开始。N-1为木板个数,M代表探测次数。
接下来一行是N-1个整数,表示每块木板的高度。
然后是M行,(x,y,z)三个数表示在编号为x的水箱中测试y+0.5米高的地方是否有水,z=0表示没有水, z=1表示有水。

输出

可能的正确探测数目的最大值。

Sample Input

2
3 4
3 4
1 3 1
2 1 0
2 2 0
3 3 1
2 2
2
1 2 0
1 2 1

Sample Output

Case #1: 3
Case #2: 1

提示

对于sample input中的第一组数据,认为第一次探测错误,那么可能的正确探测数目的最大值就就是3。

ac代码

//HDOJ_5575_AC
#include #include #include #include using namespace std;
//多组测试case时,可以复用数组,不需动态申请用完再回收。
const int MAX_N = 1e5 + 1;
const int MAX_M = MAX_N * 2;
const int INF = 1e10 + 1;
typedef pairHeightAndTankNo; struct LeftistTreeNode; int caseNum = 0, caseNo = 0, answer = 0; int n, detectNum; int leftHeightOfTank[MAX_N], rightHeightOfTank[MAX_N]; //第i个水箱的相邻水箱编号, 水箱合并时会用 int LeftTank[MAX_N],RightTank[MAX_N]; //有水探测,无水探测 int hasWaterDetect[MAX_N], noWaterDetect[MAX_N]; //有水探测对应的数组 vectorhasWaterDetectVector; //leftistTree[i] 表示 第i个水箱对应的左偏树节点编号 int leftistTree[MAX_N]; int unionFindSet[MAX_N]; //左偏树节点编号,通过自增来用 int lefttistNodeNo; //node[i] means i-th node LeftistTreeNode *nodes; struct LeftistTreeNode { int value; int dist; int lchild, rchild; LeftistTreeNode() { value = lchild = rchild = 0; dist = 1; } static void init() { if (nodes == NULL) nodes = new LeftistTreeNode[MAX_M]; for (int i = 0; i < MAX_M; i++) { nodes[i].value = nodes[i].lchild = nodes[i].rchild = 0; nodes[i].dist = 1; } } /** * * @param a tree * @param b tree * @return new root */ static int merge(int a, int b) { if (a == 0) return b; if (b == 0) return a; //小顶堆 if (nodes[a].value > nodes[b].value) swap(a, b); nodes[a].rchild = merge(nodes[a].rchild, b); if (nodes[nodes[a].lchild].dist < nodes[nodes[a].rchild].dist) swap(nodes[a].lchild, nodes[a].rchild); nodes[a].dist = nodes[nodes[a].rchild].dist + 1; return a; } /** * @param a tree * @param b new node * @return new root */ static int insert(int a, int b) { return merge(a, b); } /** * delete the top element and return new root */ static int pop(int a) { return merge(nodes[a].lchild, nodes[a].rchild); } }; //并查集 struct UnionFindSet { static void init() { for (int i = 0; i < MAX_N; i++) unionFindSet[i] = i; } static int findParent(int x) { return unionFindSet[x] == x ? x : unionFindSet[x] = findParent(unionFindSet[x]); } static void merge(int x, int y) { unionFindSet[y] = unionFindSet[x]; } }; struct Main { void read() { cin >> n >> detectNum; //第i个木板的高度, 也就是第i个水箱的右挡板的高度 for (int i = 1; i < n; i++) cin >> rightHeightOfTank[i]; } void init() { answer = 0; UnionFindSet::init(); LeftistTreeNode::init(); hasWaterDetectVector.clear(); leftHeightOfTank[1] = rightHeightOfTank[n] = INF; LeftTank[n] = n - 1; lefttistNodeNo = 0; for (int i = 1; i < n; i++) { leftHeightOfTank[i + 1] = rightHeightOfTank[i]; LeftTank[i] = i - 1; RightTank[i] = i + 1; } for (int i = 1; i <= n; i++) { hasWaterDetect[i] = noWaterDetect[i] = 0; leftistTree[i] = 0; } } void calc() { while (detectNum--) { int x, y, z; //(x,y,z)表示 在编号为x的水箱中测试y+0.5 米高的地方是否有水,z=0表示没有水, z=1表示有水。 cin >> x >> y >> z; //有水,放数组 if (z) hasWaterDetectVector.push_back(HeightAndTankNo(y + 0.5, x)); //没水 else { //每次无水探测, 答案+1 answer++; //每次无水探测对应一棵 左偏树 nodes[++lefttistNodeNo].value = y; //x号水箱无水探测的最低位置 leftistTree[x] = leftistTree[x] != 0 ? LeftistTreeNode::merge(leftistTree[x], lefttistNodeNo) : lefttistNodeNo; } } //while (detectNum--) sort(hasWaterDetectVector.begin(), hasWaterDetectVector.end()); for (unsigned int i = 0; i < hasWaterDetectVector.size(); i++) { int tankNo = UnionFindSet::findParent( hasWaterDetectVector[i].second); //探测到有水的高度 float height = hasWaterDetectVector[i].first; //水位向左溢出 while (height > leftHeightOfTank[tankNo]) { mergeTank(tankNo, LeftTank[tankNo]); tankNo = UnionFindSet::findParent(tankNo); } //水位向右溢出 while (height > rightHeightOfTank[tankNo]) { mergeTank(tankNo, RightTank[tankNo]); tankNo = UnionFindSet::findParent(tankNo); } while (leftistTree[tankNo] != 0 && nodes[leftistTree[tankNo]].value < height) { leftistTree[tankNo] = LeftistTreeNode::pop(leftistTree[tankNo]); noWaterDetect[tankNo]++; } if (++hasWaterDetect[tankNo] >= noWaterDetect[tankNo]) { answer += (hasWaterDetect[tankNo] - noWaterDetect[tankNo]); hasWaterDetect[tankNo] = noWaterDetect[tankNo] = 0; } } } void output() { cout << "Case #" << ++caseNo << ": " << answer << endl; } void mergeTank(int x, int y) { x = UnionFindSet::findParent(x); y = UnionFindSet::findParent(y); if (x == y) return; UnionFindSet::merge(x, y); //x在左,y在右 if (x < y) { rightHeightOfTank[x] = rightHeightOfTank[y]; LeftTank[RightTank[x]] = x; RightTank[x] = RightTank[y]; } else { leftHeightOfTank[x] = leftHeightOfTank[y]; RightTank[LeftTank[x]] = x; LeftTank[x] = LeftTank[y]; } leftistTree[x] = LeftistTreeNode::merge(leftistTree[x], leftistTree[y]); noWaterDetect[x] += noWaterDetect[y]; hasWaterDetect[x] += hasWaterDetect[y]; } void entry() { cin >> caseNum; while (caseNum--) { read(); init(); calc(); output(); } } }; int main() { std::ios::sync_with_stdio(false); //HDOJ系统在运行时会注入ONLINE_JUDGE这个宏定义 #ifndef ONLINE_JUDGE freopen("d:\\code-practice\\in.txt", "r", stdin); #endif Main().entry(); return 0; } 

树形DP+并查集+左偏树, HDU-5575,Discover Water Tank,2015上海现场赛D题相关推荐

  1. HDU5575 Discover Water Tank 2015上海现场赛D题 (树形dp,并查集,左偏树)

    题目大意: 有一个1维的长度为N,高度无限的水柜,现在要用N-1个挡板将其分为N个长度为1的小格,然后向水柜中注水,水可以低于挡板也可以以溢出去(这样就要与旁边格子的水位相同),现在有M次探测,探测i ...

  2. HDU 5575 Discover Water Tank 并查集+左偏树

    不妨假定初始答案为所有的无水询问,因为这样一定没有冲突. 然后枚举有水询问.水位线到这里时,答案能否更优. 若水位线达到某一高度,则可能淹没旁边的水箱,那么实际就变成了一个大水箱,所以考虑用并查集来优 ...

  3. hdu 5575 Discover Water Tank 左偏树

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5575 题意: 现在有一个巨大的水库(可视为二维的),水库中间被 n−1n-1n−1 个挡板分成了 n ...

  4. HDU 5575 Discover Water Tank(左偏树)

    https://vjudge.net/problem/HDU-5575 题意: 有一个水箱,被n-1块板子分成了n个部分,板子的高度不尽相同.现在有m次探测,每次探测在第x部分的y+0.5高度处是否有 ...

  5. HDU 5575 Discover Water Tank 并查集 树形DP

    题意: 有一个水槽,边界的两块板是无穷高的,中间有n-1块隔板(有高度),现有一些条件(i,y,k),表示从左到右数的第i列中,在高度为(y+0.5)的地方是否有水(有水:k = 1),问最多能同时满 ...

  6. HDU 5575 Discover Water Tank(线段树+自底向上dp+并查集)

    题意 给定n个挡板和m次回答,每次回答为x号水池的H+0.5高度是否有水,问这些回答互不矛盾的最大集合. 题解 设定状态dp[i][0-1]代表第i个区间枚举到当前回答后有水的最大不矛盾集合和没水的最 ...

  7. hdu-----(4514)湫湫系列故事——设计风景线(树形DP+并查集)

    湫湫系列故事--设计风景线 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) To ...

  8. 线段树合并(HDU-5575 Discover Water Tank)

    题目连接 题意: 给你一个长为n,宽为1,高为无穷的水缸.里面有n-1个高度不一的隔板隔开为1x1大小的区域.里面的水遵循物理定理.给你m次查询和回应,每个查询<x,y,z>.代表查询第x ...

  9. 可并堆——左偏树 Leftist Heap

    今天学习了左偏树,这是一个好理解而且好写的数据结构,和二叉堆一样可以在O(1)时间内取出优先级最高的值,O(logn)时间内删除优先级最高的值,不同的是如果要合并两个堆那么二叉堆就只能跪了.而左偏树能 ...

最新文章

  1. 2021年大数据常用语言Scala(十六):基础语法学习 列表 List 重点掌握
  2. 图卷积神经网络(GCN)入门
  3. C++ : 编译单元、声明和定义、头文件作用、防止头文件在同一个编译单元重复引用、static和不具名空间...
  4. 利用尾递归减少栈空间的消耗
  5. CodeForces - 1368F Lamps on a Circle(交互+贪心)
  6. cocos怎么把res文件夹放服务器上,cocos2d 三合一跑胡子房卡+服务器组件+后台控制+安装教程+棋牌完整源码...
  7. xampp命令行连接MySql数据库
  8. 自动化运维python学习笔记一
  9. 颜色空间缩减,降低运算复杂度,保留代表性颜色
  10. 线性代数及其应用笔记
  11. 什么是CDN,简单了解CDN
  12. 山腰中的AMD,向前是唯一的选择
  13. 莫比乌斯圈matlab,神奇的莫比乌斯圈(PPT).ppt
  14. 关于用指针实现输入字符串以单词为元素反转输出思路
  15. java软件工程师 英文简历_java工程师英文简历范文
  16. android 手机 平板同屏,酷乐视Q6投影仪Android手机/平板同屏方法汇总
  17. 应用程序无法正常启动(0xc000007b)解决
  18. RGB LED 七彩跳变
  19. 神经放射学诊断中的MRI数据分析
  20. 新时期下大型数据中心机房给排水及消防设计要点分析

热门文章

  1. FFplay源码分析-avformat_open_input
  2. 惠普服务器启动时主板显示40,HP 600G1 DM小主机低温不能启动,开机无显电源键红灯伴4长声报警...
  3. 如何在https网页发送http请求
  4. 用Photoshop滤镜轻松制作炫彩背景(转)
  5. DNS服务器的安装与配置(VM虚拟机)
  6. “跨境理财通”启动,大湾区居民迎来投资“新高速”
  7. 聚美优品Android面试题,聚美优品PHP面试题
  8. 作品分享:基于STM32的温度报警器含源码、原理图、PCB文件、作品报告
  9. 记录ubuntu启动卡在logo界面有鼠标进不了桌面的经历,以及安装ubuntu踩的坑
  10. .net 文字转语音简单应用 SpeedSynthesis,部署IIS