题意

给定n个挡板和m次回答,每次回答为x号水池的H+0.5高度是否有水,问这些回答互不矛盾的最大集合。

题解

设定状态dp[i][0-1]代表第i个区间枚举到当前回答后有水的最大不矛盾集合和没水的最大不矛盾集合。1代表有水,0代表没水。
我们将回答的H从小到大排序后升序枚举,对于第i个回答,我们可以用线段树定位出其所影响的区间[l,r]在这个区间内去进行dp转移。同时我们还发现若枚举到了一定的高度,我们可以进行区间与区间的合并(由于高度是递增枚举的),规定向右合并,这里用并查集就可以维护。
之后我们就可以写出转移(设枚举到的回答有水为op=1,没水为op=0)
dp[r][1]=∑i=lrdp[i][1]+op?1:0dp[r][1]=\sum_{i=l}^{r}{dp[i][1]}+op?1:0dp[r][1]=∑i=lr​dp[i][1]+op?1:0
dp[r][0]=∑i=lrmax(dp[i][0],dp[i][1])+op?0:1dp[r][0]=\sum_{i=l}^{r}{max(dp[i][0],dp[i][1])}+op?0:1dp[r][0]=∑i=lr​max(dp[i][0],dp[i][1])+op?0:1
之后将所有l-r的集合合并到r上
最后统计答案的时候只需要将剩余的集合每个聚合取max(dp[i][0],dp[i][1])max(dp[i][0],dp[i][1])max(dp[i][0],dp[i][1])累加起来即可

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
#include <cmath>
#include <vector>
#include <map>
#include <cstring>
#include <queue>
#include <stack>using namespace std;typedef long long ll;
typedef double db;
typedef unsigned long long ull;
#define PB push_back
#define MP make_pair
#define Fi first
#define Se secondconst int N=3e5+7,M=2e6+7;
struct node{int x,H,op;
}que[N];
int fa[N],h[N];
int n,m;
bool cmp(node a,node b){return a.H<b.H;
}
int cha(int x){if(fa[x]==x) return x;return fa[x]=cha(fa[x]);
}
int Max(int a,int b){return a > b?a:b;}
namespace sgt
{#define mid ((l+r)>>1)int maxx[N<<2];void up(int rt){maxx[rt] = Max(maxx[rt<<1],maxx[rt<<1|1]);}void build(int rt,int l,int r){if(l==r){maxx[rt] = h[l];return;}build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);up(rt);}int query_l(int rt,int l,int r,int x,int y,int v){if(maxx[rt]<=v) return -1;if(l==r){return l;}int ans = -1;if(y>mid) ans = query_l(rt<<1|1,mid+1,r,x,y,v);if(ans==-1&&x<=mid) ans = query_l(rt<<1,l,mid,x,y,v);return ans;}int query_r(int rt,int l,int r,int x,int y,int v){if(maxx[rt]<=v) return -1;if(l==r) return l;int ans = -1;if(x<=mid) ans =query_r(rt<<1,l,mid,x,y,v);if(ans==-1&&mid<y) ans = query_r(rt<<1|1,mid+1,r,x,y,v);return ans;}#undef mid
}
int get(int x,int v,int flag)
{if(flag==0){if(x==1) return -1;int xb = sgt::query_l(1,1,n,1,x-1,v);return xb;}else{int xb = sgt::query_r(1,1,n,x,n,v);return xb;}
}
int dp[N][3];
int main(){//freopen("d.txt","r",stdin);int t;int ti=0;scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);memset(dp,0,sizeof(dp));for(int i=1;i<=n-1;i++){scanf("%d",&h[i]);}h[n]=1e9+7;sgt::build(1,1,n);for(int i=1;i<=n+3;i++) fa[i]=i;for(int i=1;i<=m;i++){scanf("%d%d%d",&que[i].x,&que[i].H,&que[i].op);}sort(que+1,que+1+m,cmp);for(int i=1;i<=m;i++){int now=que[i].x;int l=get(que[i].x,que[i].H,0);int r=get(que[i].x,que[i].H,1);if(l==-1) l=1;else l++;//cout<<l<<' '<<r<<' '<<que[i].H<<endl;int x=cha(l);int y=cha(r);//cout<<x<<' '<<y<<' '<<queif(x==y){int res1=0,res0=0;if(que[i].op==1){res0=max(dp[y][1],dp[y][0]);res1=dp[y][1]+1;}else {res0=max(dp[y][1],dp[y][0])+1;res1=dp[y][1];}dp[y][1]=res1;dp[y][0]=res0;}else {int res1=0,res0=0;while(x!=y){if(que[i].op==1){res0+=max(dp[x][1],dp[x][0]);res1+=dp[x][1];}else {res0+=max(dp[x][1],dp[x][0]);res1+=dp[x][1];}fa[x]=cha(x+1);x=cha(x);}if(que[i].op==1){res0+=max(dp[y][1],dp[y][0]);res1+=dp[y][1]+1;}else {res0+=max(dp[y][1],dp[y][0])+1;res1+=dp[y][1];}dp[y][1]=res1;dp[y][0]=res0;}//cout<<"-----"<<que[i].H<<' '<<que[i].op<<endl;//cout<<dp[y][1]<<' '<<dp[y][0]<<endl;}int x=cha(1);int y=cha(n);int ans=0;while(x!=y){ans+=max(dp[x][0],dp[x][1]);//ans+=dp[x][1];x=cha(x+1);}ans+=max(dp[y][1],dp[y][0]);//ans+=dp[y][1];printf("Case #%d: %d\n",++ti,ans);}return 0;
}

HDU 5575 Discover Water Tank(线段树+自底向上dp+并查集)相关推荐

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

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

  2. hdu 5575 Discover Water Tank 左偏树

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

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

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

  4. HDU 5575 Discover Water Tank

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

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

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

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

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

  7. hdu 3016 Man Down(简单线段树简单DP)

    Man Down Time Limit: 2000/1000 MS (Java/Others)Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  8. BZOJ 2733 线段树的合并 并查集

    思路: 1.线段树合并(nlogn的) 2.splay+启发式合并 线段树合并比较好写 我手懒 //By SiriusRen #include <cstdio> #include < ...

  9. CF938G Shortest Path Queries(线性基,线段树分治,并查集)

    CF938G Shortest Path Queries Solution 套路题. xorxorxor最短路可以用线性基维护(把每个环的边权异或和放进线性基,询问时把树边路径边权异或和放在线性基里跑 ...

最新文章

  1. git github 快速入门
  2. docker desktop ubuntu镜像_资深专家都知道的顶级 Docker 命令!
  3. 130道ASP.NET面试题
  4. winform教_电脑绝技教你22天学精Csharp之第十五天winform应用程序补充5
  5. 作者:叶郁文,男,中兴通讯股份有限公司产品规划部长。
  6. Disruptor 创建过程
  7. 考不上本科就是低智商?用python爬3000条数据狠打脸
  8. 23种设计模式(二十三)行为变化之访问器
  9. 计算机病毒计算机中的程序是吗,计算机病毒是一种程序吗?
  10. 代做matlab程序价格,代做data collection、Matlab设计代写、Matlab代做、代做Matlab编程代写R语言程序|代做R语言编程...
  11. 【系统辨识】最小二乘法
  12. Y7000开机出现Checking media无法开机
  13. 图文并茂的学习笔记--微信小程序自定义tabbar
  14. 动脉自旋标记磁共振(ASL)的神经放射学家指南
  15. php源码 视频通讯,抖音无水印视频解析php源码
  16. 软件外包开发流程及管理
  17. squid 配置二级代理 redhat9---轻松配置
  18. 复选框 遍历选中 php,jQuery的复选框选择并且获取值
  19. 使用hugo生成静态页面,并部署到腾讯云的云开发环境。
  20. SQLmap学习笔记

热门文章

  1. 有关Linux系统的菜鸟和大牛的差距
  2. 【记录22】选择多条数据,变一条文本数据,并加复制功能
  3. 浴火重生坐上头把交椅 中国光伏加快出海步伐
  4. 【如何搭建一个高并发的抢券系统,QPS上万】
  5. 微服务项目下冗余数据如何同步?
  6. 基于Qt Creator的简单智能门锁设计
  7. 【系】微信小程序云开发实战坚果商城-云开发之商品信息和主题商品数据实现
  8. 小程序商城+公众号+线上线下相结合
  9. nginx之nginx.cof详解
  10. 交换友情链接的注意事项