雅礼集训 2017 Day2 水箱 可并堆
题目描述
给出一个长度为 n 宽度为 1 ,高度无限的水箱,有 n−1 个挡板将其分为 n 个 1 - 1 的小格,然后向每个小格中注水,水如果超过挡板就会溢出到挡板的另一边,这里的水是满足物理定律的(在无挡板阻拦的情况下会向低处流),现在有 m 个条件 (i,y,k) ,表示从左到右数的第 i 个格子中,在高度为 y+0.5 的地方是否有水,k=1 表示有水,k=0 表示没有水,请求出这 m 个条件最多能同时满足多少个条件。本题有多组数据。
输入格式
第一行一个正整数 T ,为数据组数。
第二行两个正整数 n 、m ,中间用空格隔开。
接下来一行 n−1 个整数,表示从左到右每一块隔板的高度。
接下来 m 行,每行三个整数 i 、y 、k ,表示一个条件。
输出格式
共 T 行,每行对应一组数据的答案。
样例
样例输入
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
样例输出
3
1
数据范围与提示
对于 20% 的数据,n,m≤16;
对于另外 10% 的数据,只存在指明某处有水的条件;
对于另外 30% 的数据,n,m≤1000;
对于 100% 的数据,n,m≤1e5,T≤5;
看到这道题,首先应该想到最高的隔板把整个区间分割成两个独立的部分,所以对于整段的答案,可以是左右两个部分的独立的答案(即水没有淹没最高的那个隔板),或者先把两个部分淹没,让水没过最高的隔板,然后在两侧最近的更高的隔板(箱壁可视为无限高的隔板)的高度以下讨论答案。
我用的是线段树维护区间最高挡板位置,用可并堆维护区间所有要求。
初始时,对于每一个单位水槽,把它上方所有要求按高度维护小根堆,合并时就先直接合并它左右两个部分,再将堆中左右小于两侧隔板高度的要求按照顺序提出来,枚举淹没高度,用前缀有水条件个数加后缀无水条件个数更新答案,设这个答案最大值为sum。
对于区间[L,R],若L=R,ans(L,R)=sum。
否则,[L,R]一定能从最高的隔板处分为[L,k],[k+1,R],两个部分,
可以用ans(L,k)+ans(k+1,R)+高于第k和第k+1之间的隔板低于L外侧隔板且低于R外侧隔板间所有无水条件的个数更新答案,
也可以用所有[L,R]之间低于第k和第k+1之间的隔板的有水条件个数+sum更新答案。
是的有点像分治...

复杂度分析的话,每个隔板可以和左侧比它高的第一个隔板和右侧比它高的第一个隔板分别形成两个区间,所以大概有2n个区间吧...然后每个要求在可并堆中共计被访问一次,删除一次,所以再加一个mlogm,肯定是能过的。
AC代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 200020
#define mid (l+r>>1)
using namespace std;
int read(){
int nm=0,fh=1;char cw=getchar();
for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
return nm*fh;
}
struct req{int pos,hs,tpe;}p[M];
bool cmp(req i,req j){
if(i.pos==j.pos) return i.hs<j.hs;
return i.pos<j.pos;
}
int n,m,T,tmp,L[M],R[M],c[M<<2],t[M],ans,rt[M<<2],f[M<<2];
int tot[M<<2],dst[M<<2],son[M][2],fs[M],gt[M],pre[M],suf[M],tk;
void build(int x,int l,int r){
if(l==r){c[x]=l;return;}
build(x<<1,l,mid),build(x<<1|1,mid+1,r);
if(t[c[x<<1]]>t[c[x<<1|1]]) c[x]=c[x<<1];
else c[x]=c[x<<1|1];
}
int top(int x,int l,int r,int lt,int rt){
if(rt<l||r<lt) return lt;
if(lt<=l&&r<=rt) return c[x];
int t1=top(x<<1,l,mid,lt,rt),t2=top(x<<1|1,mid+1,r,lt,rt);
return t[t1]>t[t2]?t1:t2;
}
int merge(int x,int y){
if(x*y==0) return x+y;
if(p[x].hs>p[y].hs) return merge(y,x);
int t1=son[x][0],t2=son[x][1],k=merge(t2,y);
son[x][1]=k;
if(dst[k]>dst[t1]) swap(k,t1);
dst[x]=dst[k]+1,son[x][0]=t1,son[x][1]=k;
return x;
}
int del(int x){
int t1=son[x][0],t2=son[x][1];
son[x][0]=son[x][1]=dst[x]=0;
return merge(t1,t2);
}
void dp(int &x,int l,int r){
x=++tmp,f[x]=tot[x]=0;
int cnt=0,rf=min(t[l-1],t[r]),sum=0;
if(l==r) rt[x]=fs[l];
else{
int tp=top(1,1,n-1,l,r-1);
dp(L[x],l,tp),dp(R[x],tp+1,r);
rt[x]=merge(rt[L[x]],rt[R[x]]);
tot[x]=tot[L[x]]+tot[R[x]];
}
while(rt[x]>0){
if(p[rt[x]].hs>=rf) break;
if(p[rt[x]].tpe==1) tot[x]++;
gt[++cnt]=rt[x],rt[x]=del(rt[x]);
}
suf[cnt+1]=0,pre[0]=0;
for(int i=1;i<=cnt;i++){
pre[i]=pre[i-1],suf[cnt-i+1]=suf[cnt-i+2];
if(p[gt[i]].tpe==1) pre[i]++;
if(p[gt[cnt-i+1]].tpe==0) suf[cnt-i+1]++;
}
for(int i=0;i<=cnt;i++){
if(p[gt[i]].hs==p[gt[i+1]].hs&&i!=0) continue;
sum=max(sum,pre[i]+suf[i+1]);
}
if(l==r){f[x]=sum;return;}
f[x]=max(f[L[x]]+f[R[x]]+suf[1],tot[L[x]]+tot[R[x]]+sum);
}
int main(){
T=read();
while(T--){
n=read(),m=read(),tmp=ans=tk=0,t[0]=t[n]=2147483646;
memset(fs,0,sizeof(fs));
for(int i=1;i<n;i++) t[i]=read();
for(int i=1;i<=m;i++) p[i].pos=read(),p[i].hs=read(),p[i].tpe=read();
build(1,1,n-1),sort(p+1,p+m+1,cmp);
for(int i=1;i<=m;i++){fs[p[i].pos]=merge(i,fs[p[i].pos]);}
dp(tk,1,n),printf("%d\n",f[tk]);
}
return 0;
}
雅礼集训 2017 Day2 水箱 可并堆的更多相关文章
- 「雅礼集训 2017 Day2」解题报告
「雅礼集训 2017 Day2」水箱 我怎么知道这种题目都能构造树形结构. 根据高度构造一棵树,在树上倍增找到最大的小于约束条件高度的隔板,开一个 \(vector\) 记录一下,然后对于每个 \(v ...
- #6034. 「雅礼集训 2017 Day2」线段游戏 李超树
#6034. 「雅礼集训 2017 Day2」线段游戏 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统 ...
- 【loj6034】「雅礼集训 2017 Day2」线段游戏
#6034. 「雅礼集训 2017 Day2」线段游戏 内存限制:256 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统 评测方式:Special Judge 上传者: 匿名 题目描述 ...
- loj #6032. 「雅礼集训 2017 Day2」水箱 线段树优化DP转移
$ \color{#0066ff}{ 题目描述 }$ 给出一个长度为 \(n\) 宽度为 \(1\) ,高度无限的水箱,有 \(n-1\) 个挡板将其分为 \(n\) 个 \(1 - 1\) 的小格, ...
- 「雅礼集训 2017 Day2」水箱 (数据结构+dp ,一个log)
题面 题解 在网上看到有些做法,有什么平衡树.启发式合并等等总之复杂度O(Tnlog^2(n))的不优做法,这里我就用一个O(Tnlogn)的做法好了 其实大体上推导的思路都是一样的. 我们很容易发现 ...
- loj#6032. 「雅礼集训 2017 Day2」水箱(并查集 贪心 扫描线)
题意 链接 Sol 神仙题+神仙做法%%%%%%%% 我再来复述一遍.. 首先按照\(y\)坐标排序,然后维护一个扫描线从低处往高处考虑. 一个连通块的内状态使用两个变量即可维护\(ans\)表示联通 ...
- LOJ#6032. 「雅礼集训 2017 Day2」水箱
传送门 首先可以有一个平方复杂度的 \(DP\) 设 \(f_{i,j}\) 表示前面 \(i\) 个小格,高度为 \(j\) 的最大答案 令 \(h_i\) 表示隔板 \(i\) 的高度 当 \(j ...
- 「雅礼集训 2017 Day2」水箱
题目链接 题意分析 我们用\(f[i][j]\)表示当前到达第\(i\)个位置水位高度为\(j\)的答案 如果那么\(h[i]\)为\(i\)和\(i+1\)之间的支柱高度 那么如果\(j≤h[i]\ ...
- loj#6033. 「雅礼集训 2017 Day2」棋盘游戏(二分图博弈)
题意 链接 Sol 第一次做在二分图上博弈的题..感觉思路真是清奇.. 首先将图黑白染色. 对于某个点,若它一定在最大匹配上,那么Bob必胜.因为Bob可以一直沿着匹配边都,Alice只能走非匹配边. ...
随机推荐
- 再遇xdebug坑
xdebug.remote_handler=dbgp xdebug.idekey=PHPSTORM ;开启远程调试 xdebug.remote_enable = On ;远程主机 xdebug.rem ...
- OSI模型第三层网络层-初识路由协议
1.路由协议: 顾名思义就是路由器所使用的协议. 分类: (1)按照作用范围分类,IGP(类型)内部网关协议(rip,ospf,isis),EGP(类型)边界路由协议(bgp) 把互联网比作整个世界土 ...
- 【python】-- RabbitMQ 安装、基本示例、轮询机制
RabbitMQ MQ全称为Message Queue, 是一种分布式应用程序的的通信方法,它是消费-生产者模型的一个典型的代表,producer往消息队列中不断写入消息,而另一端consumer则可 ...
- Django 之restframework1
Restframework 这里先简单的介绍一下restful协议 ----一切皆是资源,操作只是请求方式 基于restful协议的框架有很多Django下的restframework只是其中的一种 ...
- 怎样将lua移植到arm平台的linux内核
将脚本移植到内核是一件非常酷的事情,lua已经被移植到NetBSD的内核中,也有一个叫lunatik的项目把lua移植到了linux内核.仅仅可惜仅仅支持x86.不支持arm,在网上搜索了下,没有找到 ...
- 【Android】开源项目汇总
Android开源项目第一篇——个性化控件(View)篇 包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.Progres ...
- PHP eval函数使用介绍
eval()函数中的eval是evaluate的简称,这个函数的作用就是把一段字符串当作PHP语句来执行. 复制代码代码如下: eval("echo'hello world';") ...
- cloudera impala编译 安装 配置 启动
无论是采用GDB调试impala或者尝试修改impala源码,前提都是需要本地环境编译impala,这篇文章详细的分享一下impala编译方法以及编译过程遇到的棘手的问题: 前言: impala官方的 ...
- PAT 天梯赛 L2-003. 月饼 【贪心】
题目链接 https://www.patest.cn/contests/gplt/L2-003 思路 用贪心思路 最后注意一下 总售价有可能是浮点数 AC代码 #include <cstdio& ...
- ios中文模糊搜索兼容问题
$(function(){ var cpLock = true; $("input[name='name']").off().on({ compositionstart: func ...