Vases and Flowers HDU - 4614线段树+主席树思维/二分
Posted 1024-xzx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vases and Flowers HDU - 4614线段树+主席树思维/二分相关的知识,希望对你有一定的参考价值。
题意:
给出 (n) 个花瓶,编号 ([0,n-1]),一开始每个花瓶是空的。输入 (K)。(Alice) 有两种操作,共 (m) 个:
(K=1):输入 (A,F)。(Alice) 将从花瓶 (A) 开始,向空花瓶中插入花,如果没有插完,则多余的花舍弃;
(K=2):输入 (A,B)。(Alice) 建将把花瓶 (A,B) 之间的花清除掉,求出清除的花的数量,(Aleq B);
数据范围: (1 < N,M < 50001)
分析1:
??主席树求区间第 (k) 大的思想。以 (1) 表示花瓶为空,(0) 表示花瓶有花,把区间变成 ([1,n]),输入位置相应 (+1)。当进行插花操作时,我们先求出 ([A,N]) 区间内的空花瓶数目,假设为 (t)。如果 (t=0),表示无法插入花;否则,我们寻找到进行插花的花瓶的左右区间端点,然后利用简单的区间修改即可完成插花操作。如何找到端点呢?我们先求出区间 ([1,A-1]) 内的空花瓶数,假设为 (p),那么只要找到整个区间的第 (p+1) 和第 (p+min(F,t)) 个空花瓶即可。这些操作,可以类比于主席树区间求第 (k) 大。
代码实现:
??注意 (lazy) 标记,不能累加,直接修改即可。
区间修改时,如果区间满足 (Lleq l;&&;r leq R) ,可以直接赋值。不用考虑区间内是否是空花瓶和有花花瓶共存的情况,(lazy) 标记下放时,也是如此。一开始把把这些区间区分开,写起来很麻烦,也任意错。具体见代码。
代码1:
#include <bits/stdc++.h>
using namespace std;
const int N=5e4+5;
int tree[N<<2],lazy[N<<2];
void build(int l,int r,int rt)
{
lazy[rt]=-1;
if(l==r)
{
tree[rt]=1;
return;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void pushdown(int ln,int rn,int rt)
{
if(lazy[rt]!=-1)
{
lazy[rt<<1]=lazy[rt];
lazy[rt<<1|1]=lazy[rt];
if(lazy[rt]==1)
{
tree[rt<<1]=ln;
tree[rt<<1|1]=rn;
}
else
{
tree[rt<<1]=0;
tree[rt<<1|1]=0;
}
lazy[rt]=-1;
}
}
void update(int l,int r,int L,int R,int val,int rt)
{
if(L<=l&&r<=R)//注意
{
tree[rt]=val*(r-l+1);
lazy[rt]=val;
return;
}
int mid=(l+r)>>1;
pushdown(mid-l+1,r-mid,rt);
if(L<=mid)
update(l,mid,L,R,val,rt<<1);
if(R>mid)
update(mid+1,r,L,R,val,rt<<1|1);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
int query1(int l,int r,int L,int R,int rt)//简单区间求和
{
if(L<=l&&r<=R)
return tree[rt];
int mid=(l+r)>>1,ans=0;
pushdown(mid-l+1,r-mid,rt);
if(L<=mid)
ans+=query1(l,mid,L,R,rt<<1);
if(R>mid)
ans+=query1(mid+1,r,L,R,rt<<1|1);
return ans;
}
int query2(int l,int r,int L,int R,int k,int rt)//求区间第k个空花瓶
{
if(l==r)
return l;
int mid=(l+r)>>1;
pushdown(mid-l+1,r-mid,rt);
if(tree[rt<<1]>=k)
return query2(l,mid,L,R,k,rt<<1);
else
return query2(mid+1,r,L,R,k-tree[rt<<1],rt<<1|1);
}
int main()
{
int t,n,m,a,b,c,cot=0;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
build(1,n,1);
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
if(a==1)
{
int t=query1(1,n,b+1,n,1);//区间求和,看是否有空花瓶
if(t==0)
printf("Can not put any one.
");
else
{
int p=(b>0?query1(1,n,1,b,1):0);//[1,b]内的花瓶数量
int star=query2(1,n,1,n,p+1,1);
int en=query2(1,n,1,n,p+min(t,c),1);
update(1,n,star,en,0,1);//插花->0
printf("%d %d
",star-1,en-1);
}
}
else
{
printf("%d
",c-b+1-query1(1,n,b+1,c+1,1));
update(1,n,b+1,c+1,1,1);//清空花瓶->1
}
}
printf("
");
}
return 0;
}
以上是关于Vases and Flowers HDU - 4614线段树+主席树思维/二分的主要内容,如果未能解决你的问题,请参考以下文章
HDU 4614 Vases and Flowers 线段树+二分
HDU4614Vases and Flowers 二分+线段树;