您的位置:首页 > 其它

poj1823线段树

2015-12-09 20:31 162 查看
题意:

有人要住旅馆,然后住在一些连续的房间里;

那么让你求空闲的连续的旅馆的最大长度;

理解:

此题认真想想应该就是线段树了;

然后合并的是区间,而不是单独的值;

合并区间就有点麻烦了;

主要就是两个区间合并的时候要注意中间是否可以再组成一个区间;‘

做法就是记录此区间的两端没有住人的两端;

然后将此区间的最大值求出来;

之后向上合并;

注意合并时要判断中间是否可以连接起来;

代码如下:(线段树就是太难写了,不过思路清晰就好写了)

#include <cstdio>

#include <algorithm>
#include <vector>

using namespace std;

#define P pair<int, int>
#define x first
#define y second

struct node
{
int len;
int flag;
P lt, rt; //左右两端的空闲区间
};

node tree[16000 * 5 + 10];
int up[16000 * 5 + 10];

node build(int l, int r, int rx)
{
if (l == r)
{
tree[rx].len = 1;
tree[rx].flag = 0;
tree[rx].lt = tree[rx].rt = P(l, r);
return tree[rx];
}

node n1 = build(l, (l + r) / 2, rx * 2);
node n2 = build((l + r) / 2 + 1, r, rx * 2 + 1);
tree[rx].len = n1.len + n2.len;
tree[rx].flag = 0;
tree[rx].lt = tree[rx].rt = P(n1.lt.x, n2.rt.y);

return tree[rx];
}

void push_down(int l, int r, int rx)
{
if (l != r)
{
up[rx * 2] = up[rx];
up[rx * 2 + 1] = up[rx];
if (up[rx] == 1)
{
tree[rx * 2].len = tree[rx * 2 + 1].len = 0;

tree[rx * 2].flag = tree[rx * 2 + 1].flag = 1;

tree[rx * 2].lt
= tree[rx * 2].rt
= tree[rx * 2 + 1].lt
= tree[rx * 2 + 1].rt
= P(-1, -1);
}
else
{
tree[rx * 2].len
= (l + r) / 2 - l + 1;
tree[rx * 2 + 1].len
= r - (l + r) / 2 - 1 + 1;

tree[rx * 2].flag = tree[rx * 2 + 1].flag = 0;

tree[rx * 2].lt
= tree[rx * 2].rt
= P(l, (l + r) / 2);
tree[rx * 2 + 1].lt
= tree[rx * 2 + 1].rt
= P((l + r) / 2 + 1, r);
}
}
up[rx] = 0;
}

void update(int l, int r, int L, int R, int rx, int num)
{
if (L > r || R < l) return ;

if (L >= l && R <= r)
{
up[rx] = (num == 0 ? -1 : 1);
if (num == 0)
{
tree[rx].len = R - L + 1;
tree[rx].flag = 0;
tree[rx].lt = tree[rx].rt = P(L, R);
}
else
{
tree[rx].len = 0;
tree[rx].flag = 1;
tree[rx].lt = tree[rx].rt = P(-1, -1);
}
return ;
}

if (up[rx])
{
push_down(L, R, rx); //开始的时候push_down放错位置了,结果超时,坑
}

update(l, r, L, (L + R) / 2, rx * 2, num);
node n1 = tree[rx * 2];
update(l, r, (L + R) / 2 + 1, R, rx * 2 + 1, num);
node n2 = tree[rx * 2 + 1];

if (n1.flag != n2.flag)
{
tree[rx] = (n1.flag == 0 ? n1 : n2);
return ;
}

if (n1.flag == n2.flag && n1.flag == 1)
{
tree[rx].len = 0;
tree[rx].flag = 1;
tree[rx].lt = tree[rx].rt = P(-1, -1);
return ;
}

if (n1.rt.y + 1 == n2.lt.x)
{
tree[rx].len = max(n1.len, max(n2.len, n2.lt.y - n1.rt.x + 1));
tree[rx].flag = 0;
if (n1.lt.y < n1.rt.x)
{
tree[rx].lt = n1.lt;
}
else tree[rx].lt = P(n1.rt.x, n2.lt.y);

if (n2.lt.y < n2.rt.x)
{
tree[rx].rt = n2.rt;
}
else tree[rx].rt = P(n1.rt.x, n2.lt.y);
return ;
}

tree[rx].len = max(n1.len, n2.len);
tree[rx].flag = 0;
tree[rx].lt = n1.lt;
tree[rx].rt = n2.rt;
return ;
}

int main()
{
int n, p;
scanf("%d%d", &n, &p);
build(1, n, 1);
for (int i = 0; i < p; ++i)
{
int num;
scanf("%d", &num);
if (num == 3)
{
printf("%d\n", tree[1].len);
}
else if (num == 1)
{
int num1, num2;
scanf("%d%d", &num1, &num2);
update(num1, num1 + num2 - 1, 1, n, 1, 1);
}
else
{
int num1, num2;
scanf("%d%d", &num1, &num2);
update(num1, num1 + num2 - 1, 1, n, 1, 0);
}
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj 线段树