您的位置:首页 > 其它

POJ 3667 Hotel. (线段树 区间合并)

2014-08-11 21:47 495 查看
线段树区间合并~~~~这才是我喜欢的代码风格。

两种操作:

1、输出满足连续区间最左边的值。

2、更新一段连续区间。

题目链接:http://poj.org/problem?id=3667

so~~码之~~~

#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x7fffffff
#define lson rt<<1,s,m
#define rson rt<<1|1,m+1,e
#define N 55555
using namespace std;

struct node
{
int v;
int lm,rm,sm;
}tre[N<<2];
void build(int rt,int s,int e)
{
tre[rt].v=-1;
tre[rt].lm=tre[rt].rm=tre[rt].sm=e-s+1;
if(s==e) return ;
int m=(s+e)>>1;
build(lson);
build(rson);
}
void pushdown(int rt,int m) //成段更新操作。
{
if(tre[rt].v!=-1)
{
tre[rt<<1].v=tre[rt<<1|1].v=tre[rt].v;
tre[rt<<1].lm=tre[rt<<1].rm=tre[rt<<1].sm=tre[rt].v? 0:m-(m>>1);
tre[rt<<1|1].lm=tre[rt<<1|1].rm=tre[rt<<1|1].sm=tre[rt].v? 0:m>>1;
tre[rt].v=-1;
}
}
void pushup(int rt,int m) //区间合并操作。
{
tre[rt].lm=tre[rt<<1].lm;
tre[rt].rm=tre[rt<<1|1].rm;
if(tre[rt].lm==m-(m>>1)) tre[rt].lm+=tre[rt<<1|1].lm;
if(tre[rt].rm==(m>>1)) tre[rt].rm+=tre[rt<<1].rm;
tre[rt].sm=max(tre[rt<<1].sm,max(tre[rt<<1|1].sm,tre[rt<<1].rm+tre[rt<<1|1].lm));
}
int query(int n,int rt,int s,int e)
{
if(s==e) return s;
pushdown(rt,e-s+1);
int m=(s+e)>>1;
//因为要输出最左边的位置。
if(tre[rt<<1].sm>=n) return query(n,lson);
else if(tre[rt<<1].rm+tre[rt<<1|1].lm>=n) return m-tre[rt<<1].rm+1; //两个子区间的中间区域。
else return query(n,rson);
}
void update(int l,int r,int v,int rt,int s,int e)
{
if(l==s && r==e)
{
tre[rt].v=v;
tre[rt].lm=tre[rt].rm=tre[rt].sm=v? 0:e-s+1;
return ;
}
pushdown(rt,e-s+1);
int m=(s+e)>>1;
if(r<=m) update(l,r,v,lson);
else if(l>m) update(l,r,v,rson);
else
{
update(l,m,v,lson);
update(m+1,r,v,rson);
}
pushup(rt,e-s+1);
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
build(1,1,n);
for(int i=0;i<m;i++)
{
int op;
scanf("%d",&op);
if(op==1)
{
int num;
scanf("%d",&num);
if(tre[1].sm>=num)
{
int k=query(num,1,1,n);
printf("%d\n",k);
update(k,k+num-1,1,1,1,n);
}
else  puts("0");
}
else
{
int k,num;
scanf("%d %d",&k,&num);
update(k,k+num-1,0,1,1,n);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息