题意:

给出个水箱,水箱两侧有无限高的隔板,水箱内有整数高度的隔板将水箱分成n-1份,现在给出m个限制,每个限制表示某个位置的某个高度有水或没水,问最多能同时满足多少个限制.n,m<=2*10^5

分析:

“某个位置有水”的限制会导致从这个位置向两侧扩展的一个区间都有这个高度的水.只要找到从这个位置向左/向右第一个比这个限制的水位高的挡板即可,可以用单调栈+二分O(nlogn)求出所有区间,每个区间对应有一个高度(就是这个限制的水位高度).如果某个有水的区间对应的高度下方有一个位置存在”这个位置不能有水”的限制,那么这两个不同种类的限制就会产生矛盾,两个有矛盾的限制不能同时满足,一些限制如果两两不存在矛盾那么就可以同时满足,而且只有不同种类的限制才会产生矛盾,那么这是一个二分图最大独立集的模型,我们就可以打一个网络流暴力

仔细分析一下,我们发现两个不同的有水的限制所对应的区间要么相互包含,要么相互没有公共部分,要么完全相同.假设出现了相交但不包含的情况,不妨令两个区间为[l1,r1]和[l2,r2],且l1<l2<r1<r2,那么l1和r1一定比[l1,r1]内部的挡板高,l2和r2一定比[l2,r2]内部的挡板高,第一个限制如果越过了l2,就不应该被r1挡住,第二个限制如果越过了r1,就不应该被l2挡住.因此所有区间要么相互包含要么相互独立.

这样,所有区间的包含关系形成了一个森林结构,可以加一个超级根连成一棵树.

那么我们如果让某个有水区间的限制满足,那么这个区间所"包含(即:横坐标范围不超出这个区间且高度在这个区间下方)"的所有区间都必须有水,而且这个区间下方所有的"没水"的限制都不能满足.最后我们肯定会选出某些子树,满足这些子树内的"有水"限制且放弃这些子树的根节点覆盖的"无水"限制(根节点的区间的覆盖范围是最大的).

那么将所有限制按高度排序,扫描一遍,用树状数组求出每个区间覆盖的"无水"限制的个数,用平衡树维护一下区间,把树形结构建立出来就可以了.

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cctype>
using namespace std;
void read(int &x){
char ch;while(ch=getchar(),!isdigit(ch));
x=ch-'';
while(ch=getchar(),isdigit(ch))x=x*+ch-'';
}
const int maxn=;
vector<int> num[maxn];
int n,m;
int h[maxn];
int l[maxn],r[maxn];
int x[maxn],y[maxn],typ[maxn];
int binary(int *stk,int l,int r,int x){
while(l<=r){
int mid=(l+r)>>;
if(h[stk[mid]]>=x)l=mid+;
else r=mid-;
}
return stk[l-];
}
void init(){
static int stk[maxn],top=;
top=;
for(int i=;i<=n;++i){
num[i].clear();
}
for(int i=;i<=m;++i){
if(typ[i]==)num[x[i]].push_back(i);
}
stk[top++]=;
for(int i=;i<=n;++i){
for(vector<int>::iterator pt=num[i].begin();pt!=num[i].end();++pt){
l[(*pt)]=binary(stk,,top-,y[*pt]+);
}
while(h[stk[top-]]<h[i]){
top--;
}
stk[top++]=i;
}
top=;stk[top++]=n;
for(int i=n;i>=;--i){
for(vector<int>::iterator pt=num[i].begin();pt!=num[i].end();++pt){
r[*pt]=binary(stk,,top-,y[*pt]+);
}
while(h[stk[top-]]<h[i-]){
top--;
}
stk[top++]=i-;
}
}
int sum[maxn];//sum[i]:limitation i of typ1 contain how many limatation of typ0
int c[maxn];
void add(int x){
for(;x<maxn;x+=x&(-x))c[x]++;
}
int pre(int x){
int ans=;
for(;x;x-=x&(-x))ans+=c[x];
return ans;
}
int seq[maxn];
bool cmp(const int &a,const int &b){
return (y[a]==y[b])?typ[a]<typ[b]:y[a]<y[b];
}
struct edge{
int to,next;
}lst[maxn<<];int first[maxn],len=;
void addedge(int a,int b){
lst[len].to=b;lst[len].next=first[a];first[a]=len++;
}
struct node{
int l,r,num,ord,sz;
node* ch[];
node(){}
node(int L,int R,int N){
ch[]=ch[]=;
l=L;r=R;num=N;ord=rand();sz=;
}
void update(){
sz=;
if(ch[])sz+=ch[]->sz;
if(ch[])sz+=ch[]->sz;
}
}t[maxn*];int tsz=;
node* newnode(int L,int R,int x){
t[++tsz]=node(L,R,x);return t+tsz;
}
void rot(node* &rt,int t){
node* c=rt->ch[t];rt->ch[t]=c->ch[t^];c->ch[t^]=rt;rt=c;
c->ch[t^]->update();c->update();
}
void Insert(node* &rt,int x){
if(!rt)rt=newnode(l[x]+,r[x],x);
else{
int t=(l[x]+)>rt->l;
Insert(rt->ch[t],x);
rt->update();
if(rt->ch[t]->ord>rt->ord)rot(rt,t);
}
}
node* succ(node* rt,int x){
if(!rt)return ;
if(rt->l>=l[x]+){
node* tmp=succ(rt->ch[],x);
if(tmp)return tmp;
else return rt;
}else{
return succ(rt->ch[],x);
}
}
node* root;
void remove(node* &rt,int l){
if(rt->l!=l){
remove(rt->ch[l>rt->l],l);
rt->update();
}else{
if(!rt->ch[])rt=rt->ch[];
else if(!rt->ch[])rt=rt->ch[];
else{
if(rt->ch[]->ord>rt->ch[]->ord){
rot(rt,);remove(rt->ch[],l);
}else{
rot(rt,);remove(rt->ch[],l);
}
rt->update();
}
}
}
void traverse(node* rt){
if(!rt)return;
addedge(,rt->num);
traverse(rt->ch[]);traverse(rt->ch[]);
}
int sz[maxn],f[maxn];
void dp(int x){
if(x)sz[x]=;
else sz[x]=;
int tmp=;
for(int pt=first[x];pt;pt=lst[pt].next){
dp(lst[pt].to);sz[x]+=sz[lst[pt].to];
tmp+=max(f[lst[pt].to],);
}
f[x]=max(tmp,sz[x]-sum[x]);
}
int main(){
int cases=;
int tests;read(tests);
while(tests--){
root=;tsz=;
memset(c,,sizeof(c));
memset(first,,sizeof(first));len=;
read(n);read(m);
int cnt0=;
for(int i=;i<n;++i)scanf("%d",&h[i]);
for(int i=;i<=m;++i){
read(x[i]);read(y[i]);read(typ[i]);
if(typ[i]==)cnt0++;
}
h[]=h[n]=0x7f7f7f7f;
init();
for(int i=;i<=m;++i)seq[i]=i;
sort(seq+,seq+m+,cmp);
for(int i=;i<=m;++i){
if(typ[seq[i]]==)add(x[seq[i]]);
else{
sum[seq[i]]=pre(r[seq[i]])-pre(l[seq[i]]);
node* pt;
while((pt=succ(root,seq[i]))&&pt->r<=r[seq[i]]){
addedge(seq[i],pt->num);
remove(root,pt->l);
}
Insert(root,seq[i]);
}
}
sum[]=pre(n);
traverse(root);
dp();
printf("Case #%d: %d\n",++cases,cnt0+f[]);
}
return ;
}

hdu5575 Discover Water Tank的更多相关文章

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

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

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

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

  3. CF414D Mashmokh and Water Tanks

    CF414D Mashmokh and Water Tanks 洛谷评测传送门 题目描述 Mashmokh is playing a new game. In the beginning he has ...

  4. PID控制器(比例-积分-微分控制器)- I

    形象解释PID算法 小明接到这样一个任务: 有一个水缸点漏水(而且漏水的速度还不一定固定不变),要求水面高度维持在某个位置,一旦发现水面高度低于要求位置,就要往水缸里加水. 小明接到任务后就一直守在水 ...

  5. ZOJ 5579 Stean

    Stean Time Limit: 1 Second      Memory Limit: 65536 KB      Special Judge Tom is good at making stea ...

  6. CodeForces 362E Petya and Pipes

    Petya and Pipes Time Limit: 1000ms Memory Limit: 262144KB This problem will be judged on CodeForces. ...

  7. What are CBR, VBV and CPB?

    转自:https://codesequoia.wordpress.com/2010/04/19/what-are-cbr-vbv-and-cpb/ It's common mistake to to ...

  8. Aquarium Tank(csu1634+几何+二分)Contest2087 - 湖南多校对抗赛(2015.05.24)-G

    Aquarium Tank Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 15  Solved: 4[Submit][Status][Web Board ...

  9. [LeetCode] Pacific Atlantic Water Flow 太平洋大西洋水流

    Given an m x n matrix of non-negative integers representing the height of each unit cell in a contin ...

随机推荐

  1. The Git Parable:Git传说(转)

    The Git Parable:Git传说 -------- 毛球子好为人师 原文地址:http://tom.preston-werner.com/2009/05/19/the-git-parable ...

  2. 成都Uber优步司机奖励政策(1月28日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  3. LeetCode:49. Group Anagrams(Medium)

    1. 原题链接 https://leetcode.com/problems/group-anagrams/description/ 2. 题目要求 给定一个字符串数组,将数组中包含相同字母的元素放在同 ...

  4. 函数返回const,以便控制访问

    #include <stdio.h> class const_out_parameter{ private: ]; public: int* const_out_parameter_tes ...

  5. ElasticSearch-Java-low-level-rest-client官方文档翻译

    人肉翻译,非谷歌机翻,部分地方添加了个人的理解,并做了分割,如有错误请在评论指出.转载请指明原链接,尊重个人劳动成果.        High-Level-Rest-Client基于Low-Level ...

  6. 2019年猪年海报PSD模板-第七部分

    14套精美猪年海报,免费猪年海报,下载地址:百度网盘,https://pan.baidu.com/s/1pE3X9AYirog1W8FSxbMiAQ              

  7. 「日常训练」School Marks(Codeforces Round 301 Div.2 B)

    题意与分析(CodeForces 540B) 题意大概是这样的,有一个考试鬼才能够随心所欲的控制自己的考试分数,但是有两个限制,第一总分不能超过一个数,不然就会被班里学生群嘲:第二分数的中位数(科目数 ...

  8. 【input】输入框组件说明

    input输入框组件 原型: <input value="[String]" type="[text | number | idcard | digit]" ...

  9. python 打包

    一.下载 pip install Pyinstaller 二.使用Pyinstaller 1.使用下载安装的方式安装的Pyinstaller打包方式 将需要打包的文件放在解压得到的Pyinstalle ...

  10. Java中定时器相关实现的介绍与对比之:Timer和TimerTask

    Timer和TimerTask JDK自带,具体的定时任务由TimerTask指定,定时任务的执行调度由Timer设定.Timer和TimerTask均在包java.util里实现. 本文基于java ...