hdu5575 Discover Water Tank
题意:
给出个水箱,水箱两侧有无限高的隔板,水箱内有整数高度的隔板将水箱分成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的更多相关文章
- HDU 5575 Discover Water Tank(左偏树)
https://vjudge.net/problem/HDU-5575 题意: 有一个水箱,被n-1块板子分成了n个部分,板子的高度不尽相同.现在有m次探测,每次探测在第x部分的y+0.5高度处是否有 ...
- HDU 5575 Discover Water Tank 并查集 树形DP
题意: 有一个水槽,边界的两块板是无穷高的,中间有n-1块隔板(有高度),现有一些条件(i,y,k),表示从左到右数的第i列中,在高度为(y+0.5)的地方是否有水(有水:k = 1),问最多能同时满 ...
- CF414D Mashmokh and Water Tanks
CF414D Mashmokh and Water Tanks 洛谷评测传送门 题目描述 Mashmokh is playing a new game. In the beginning he has ...
- PID控制器(比例-积分-微分控制器)- I
形象解释PID算法 小明接到这样一个任务: 有一个水缸点漏水(而且漏水的速度还不一定固定不变),要求水面高度维持在某个位置,一旦发现水面高度低于要求位置,就要往水缸里加水. 小明接到任务后就一直守在水 ...
- ZOJ 5579 Stean
Stean Time Limit: 1 Second Memory Limit: 65536 KB Special Judge Tom is good at making stea ...
- CodeForces 362E Petya and Pipes
Petya and Pipes Time Limit: 1000ms Memory Limit: 262144KB This problem will be judged on CodeForces. ...
- 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 ...
- 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 ...
- [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 ...
随机推荐
- Java基础——注解
一.概述 引自百度百科: 定义:注解(Annotation),也叫元数据.一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性,与类.接口.枚举是在同一个层次.它可以声明在包.类.字段.方法. ...
- 算法-PHP实现八大算法
八大算法原理详解 交换函数:注意要按引用传递,否则无法真正交换两个数的值 function exchange(&$a, &$b){ $temp = $a; $a = $b; $b = ...
- 成都Uber优步司机奖励政策(3月17日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- springboot整合kafka应用
1.kafka在消息传递的使用非常普遍,相对于activemq来说kafka的分布式管理和使用更加灵活. 2.activemq的搭建和使用可以参考: activemq搭建和springmvc的整合:h ...
- svn 撤销 已提交的修改
1.保证我们拿到的是最新代码: svn update 假设最新版本号是28. 2.然后找出要回滚的确切版本号: svn log [something] 假设根据svn log日志查出要回滚的 ...
- vue2组件之间双向数据绑定问题
最近在使用element-ui的dialog组件二次封装成独立组件使用时,子组件需要将关闭dialog状态返回给父组件,简单的说就是要实现父子组件之间的数据双向绑定问题. 大致代码如下: 1,父组件 ...
- 修改Eclipse中项目在Apache Tomcat中的部署路径
在Eclipse中配项目已经部署到如下默认目录下:eclipse workspace/.metadata/.plugins/org.eclipse.core.resources/.projects. ...
- TPO-15 C1 The campus newspaper's reporter position
TPO-15 C1 The campus newspaper's reporter position 第 1 段 1.Listen to a conversation between a Studen ...
- unity实现框选效果
思路: 在uinity中既可以将屏幕坐标转换为世界坐标,也可以将世界坐标转换为屏幕坐标.这样的话我们就可以通过判断物体在世界坐标转换为平幕坐标是否在鼠标框选的矩形区域坐标内,来判断物体是否在框选范围. ...
- java后台接收微信服务号/订阅号消息
1.申请订阅号(适合个人)或者服务号(适合企业) 微信公众平台 2.填写配置 服务器地址: 需要接收消息 的服务端接口地址 令牌:通话识别码,随便写,后端接收时,使用一样的就可以了. 消息加密秘钥 : ...