https://vjudge.net/problem/HDU-5575

题意:

有一个水箱,被n-1块板子分成了n个部分,板子的高度不尽相同。现在有m次探测,每次探测在第x部分的y+0.5高度处是否有水,回答0代表没水,1代表有水。现在要求出这m次探测最多有多少次是正确的。

思路:

挺难的一道题目吧。

一开始如果把水箱当成空的,那么所有的无水探测就都是真的,至于有水探测的话,接下来我们可以一点一点的加水,这就要求将有水探测排序。每个部分可能会有多个无水探测(比如在第1部分,它进高度为1、3、5的地方都进行无水探测),那么在被淹没的时候肯定最先淹没高度为1的地方。这样的话,对于每个部分都可以建立一个优先队列,每次弹出值最小的。但是这些部分还会因为淹没而变成一部分,这时候要将两个部分的优先队列合并起来,这样的话,就是一个左偏树了。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<vector>
  4 #include<cstring>
  5 #include<algorithm>
  6 using namespace std;
  7
  8 typedef pair<int,int> pll;
  9 const int INF = 0x3f3f3f3f;
 10 const int maxn = 1e5 + 5;
 11
 12 int n,m,ans,tot;
 13 int LH[maxn],RH[maxn],L[maxn],R[maxn];
 14 int heap[maxn];
 15 int ok[maxn],nok[maxn],p[maxn];
 16
 17 vector<pll> query;
 18
 19 struct node
 20 {
 21     int l,r,dis,key;
 22 }t[2*maxn];
 23
 24 int initHeap(int x)
 25 {
 26     t[++tot].key = x;
 27     t[tot].l = t[tot].r = t[tot].dis = 0;
 28     return tot;
 29 }
 30
 31 int merge(int x, int y)
 32 {
 33     if(x == 0)  return y;
 34     if(y == 0)  return x;
 35     if(t[x].key>t[y].key)  swap(x,y);
 36     t[x].r = merge(t[x].r,y);
 37     if(t[t[x].l].dis < t[t[x].r].dis)  swap(t[x].l,t[x].r);
 38     if(t[x].r==0)  t[x].dis = 0;
 39     else t[x].dis = t[t[x].r].dis + 1;
 40     return x;
 41 }
 42
 43 int insert(int x, int y)
 44 {
 45     return merge(x,initHeap(y));
 46 }
 47
 48 int pop(int x)
 49 {
 50     return merge(t[x].l,t[x].r);
 51 }
 52
 53 int finds(int x)
 54 {
 55     return x==p[x]?x:p[x]=finds(p[x]);
 56 }
 57
 58 void unions(int x, int y)
 59 {
 60     x = finds(x);
 61     y = finds(y);
 62     if(x==y) return;
 63
 64     p[y] = x;
 65     if(x>y)  //合并两个部分
 66     {
 67         LH[x] = LH[y];
 68         L[x] = L[y];
 69     }
 70     else
 71     {
 72         RH[x] = RH[y];
 73         R[x] = R[y];
 74     }
 75
 76     heap[x] = merge(heap[x],heap[y]);  //合并两个部分的左偏树
 77     ok[x] += ok[y];
 78     nok[x] += nok[y];
 79 }
 80
 81 int main()
 82 {
 83     //freopen("in.txt","r",stdin);
 84     int T;
 85     scanf("%d",&T);
 86     int kase = 0;
 87     while(T--)
 88     {
 89         query.clear();
 90         memset(heap,0,sizeof(heap));
 91
 92         scanf("%d%d",&n,&m);
 93         LH[1] = RH[n] = INF;
 94         for(int i=1;i<n;i++)
 95         {
 96             scanf("%d",&RH[i]);
 97             LH[i+1] = RH[i];
 98             L[i] = i-1;  //i的左边
 99             R[i] = i+1;  //i的右边
100         }
101         L[n]=n-1;
102         ans = tot = 0;
103         while(m--)
104         {
105             int x,y,z;
106             scanf("%d%d%d",&x,&y,&z);
107             if(z==0)
108             {
109                 if(heap[x]==0)  heap[x] = initHeap(y);
110                 else heap[x] = insert(heap[x],y);
111                 ans++;
112             }
113             else
114             {
115                 query.push_back(make_pair(y,x));
116             }
117         }
118         sort(query.begin(),query.end());
119         for(int i=1;i<=n;i++)  ok[i]=nok[i]=0;
120         for(int i=1;i<=n;i++)  p[i] = i;
121         for(int i=0;i<query.size();i++)
122         {
123             int x = finds(query[i].second);
124             int y = query[i].first;
125             while(y>LH[x]) unions(x,L[x]);  //向左溢出
126             while(y>RH[x]) unions(x,R[x]);  //向右溢出
127             while(heap[x]!=0 && t[heap[x]].key<y)
128             {
129                 heap[x] = pop(heap[x]);
130                 nok[x]++;
131             }
132             ok[x]++;  //当前进行的是真
133             if(ok[x]>=nok[x])
134             {
135                 ans+=ok[x]-nok[x];
136                 ok[x] = nok[x] = 0;
137             }
138         }
139         printf("Case #%d: %d\n",++kase,ans);
140     }
141     return 0;
142 }

转载于:https://www.cnblogs.com/zyb993963526/p/7849543.html

HDU 5575 Discover Water Tank(左偏树)相关推荐

  1. hdu 5575 Discover Water Tank 左偏树

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

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

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

  3. hdu 5575 Discover Water Tank(可合并堆)

    题目链接:hdu 5575 Discover Water Tank 题意: 有一个大水箱,里面有N-1个隔板,将这个大水箱分成了N个小水箱,每个隔板有一定的高度. 现在有m条信息,每条信息表示第x个水 ...

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

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

  5. HDU 5575 Discover Water Tank

    原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=5575 把每个水箱当作一个并查集,每个无水的探测当做一个左偏树.有水的探测则放在数组中.并用一个数组使水 ...

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

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

  7. HDU 1512 Monkey King(左偏树+并查集)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1512 题       意: 有n个猴子,一开始每个猴子只认识自己.每个猴子有一个力量值,力量值越大表示 ...

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

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

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

    只是ACM/IICPC 2015 上海区域赛的一道题.原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=5575 题目描述 N-1个木板把一个水箱划分成了N ...

最新文章

  1. maven install 报错 source 1.5 中不支持 lambda 表达式
  2. cocos2d-x初探学习笔记(16)--LayerColor
  3. 异形3×3魔方还原教程_【理论篇】三阶魔方4.33千亿亿种变化是怎么计算出来的?...
  4. JEECG - 基于代码生成器的J2EE智能开发框架 续四: 查询条件SQL生成器设计思路
  5. 玩了10小时赛博朋克2077,我觉得很失望
  6. python之元组操作
  7. 【长文】CNN调优总结
  8. UG NX11.0 软件安装教程
  9. weka与mysql相连_Weka与MySQL连接配置
  10. Maven的setting仓库配置
  11. 证明:二阶导函数大于零时为凹函数
  12. Python+OpenCV对证件照换底
  13. 阿里云账号实名认证解决方案
  14. 库存转换是什么意思_什么是库存?
  15. 数组排序(O(n的二次方))
  16. 【数值分析/计算方法】插值法及其余项MATLAB仿真实验
  17. 双系统安装 小记 历时9小时 过关斩将! Ubuntu19.10 + RUFUS 经验之谈
  18. 计算机专业,刚上大一,该如何学习?
  19. 徐进的信念:IE工业工程与精益生产管理的区别
  20. 文献解读|植物对低温胁迫的反应:低温胁迫改变了大白菜的抗氧化代谢能力

热门文章

  1. 前端浏览器的跨域问题
  2. Python:字符串操作1(去掉空格)
  3. angular 响应式布局
  4. 多维(三维四维)矩阵向量运算-超强可视化
  5. 【Wu的课堂】《运筹学》单纯形法中文讲解笔记
  6. SMIC 14 STDCELL库的构成总结
  7. fortran print
  8. 德鲁克:你的工作效率,决定了你的薪资水平
  9. SolidCam2016/2017/2018软件中文版/绿色版安装方法
  10. 计算机专业英语每天20词-day01