树形DP+并查集+左偏树, HDU-5575,Discover Water Tank,2015上海现场赛D题
2017-01-03 17:03
435 查看
只是ACM/IICPC 2015 上海区域赛的一道题。原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=5575
接下来进行M次探测,探测指定地方指定高度有没有水。这些探测中包含错误结果,求可能的正确探测数目的最大值。
每组数据以N和M开始。N-1为木板个数,M代表探测次数。
接下来一行是N-1个整数,表示每块木板的高度。
然后是M行,(x,y,z)三个数表示在编号为x的水箱中测试y+0.5米高的地方是否有水,z=0表示没有水, z=1表示有水。
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
Case #2: 1
题目描述
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
23 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: 3Case #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 pair HeightAndTankNo; 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]; //有水探测对应的数组 vector hasWaterDetectVector; //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 = INF; LeftTank = 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; }
相关文章推荐
- HDU5575 Discover Water Tank 2015上海现场赛D题 (树形dp,并查集,左偏树)
- HDU 5575 Discover Water Tank 并查集+左偏树
- HDU 5575 Discover Water Tank(左偏树)
- 2015 上海区域赛 D Discover water tank 并查集dp+左偏树
- HDU 5575 Discover Water Tank
- HDU-5575-Discover Water Tank
- HDU 5575 Discover Water Tank(并查集+左偏树/启发式合并)
- hdu 5575 Discover Water Tank(可合并堆)
- 2015上海区域赛D题 左偏树+树形DP
- HDU 5573 Binary Tree 2015上海现场赛B题
- HDU 5514 【2015沈阳现场赛 F】 Frogs
- hdu 5510 Bazinga 2015ACM/ICPC亚洲区沈阳站现场赛
- HDU 5534 【2015长春现场赛 H】 Partial Tree
- HDU 5528【2015长春现场赛 B】 Count a * b
- HDU 5478 Can you find it 2015ICPC上海网络赛
- HDU5572 2015上海现场赛A题1001
- HDU 5512 Pagodas (2015沈阳现场赛,找规律+gcd)
- HDU 5443 The Water Problem 2015 ACM/ICPC Asia Regional Changchun Online
- HDU 5576 Expection of String (DP, 前缀和维护) 2015年上海现场赛E题
- hdu 5478 Can you find it 2015上海网络赛 数论