只是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 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[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; } 
       
      
     
    
   
  

更多推荐