您的位置:首页 > 产品设计 > UI/UE

HDU 3397 Sequence operation(线段…

2013-04-23 09:27 405 查看
题意:给个一只有0,1 的序列,有以下5种操作

0 a b change all characters into '0's in [a , b] //把a,b间的都改为0

1 a b change all characters into '1's in [a , b] //把a,b间都改为1

2 a b change all '0's into '1's and change all '1's into '0's in
[a, b] //1的改为0,0的改为1

Output operations:

3 a b output the number of '1's in [a, b] //a,b间1
的数量

4 a b output the length of the longest continuous '1' string in [a
, b]//a,b间最大连续的1的个数

思路:经典的线段树,只是操作过多,但其实很简单,相当于把以前做过的题的操作合在一块 什么值的更改,区间和的查询,最开连续的个数
。所以没什么特殊的

//1312MS
8836K

#include <stdio.h>

#define L(x) (x<<1)

#define R(x) (x<<1|1)

#define M 100010

struct tree

{

int
l,r,len; //len 是该区间的长度

int
sum,cover; //sum 是该区间1的数量,cover
有3个值-1,0,1分别表示该区间是否被0,1完全覆盖

int
lm,rm,ma;
//lm rm ma 分别表示 左连续 右连续 和最大的连续1的个数

} node[M*4];

int num[M];

int max (int a,int b)

{

return a
> b ? a : b;

}

int min (int a ,int b)

{

return a
> b ? b : a;

}

void Union (int u) //区间合并,由子结点修改父结点的信息

{
//常用手法 就不多解释了

node[u].sum
= node[L(u)].sum + node[R(u)].sum;

if
(node[L(u)].len == node[L(u)].lm)

node[u].lm = node[L(u)].len + node[R(u)].lm;

else

node[u].lm = node[L(u)].lm;

if
(node[R(u)].len == node[R(u)].rm)

node[u].rm = node[R(u)].len + node[L(u)].rm;

else

node[u].rm = node[R(u)].rm;

int a = max
(node[L(u)].ma,node[R(u)].ma);

int b = max
(node[u].lm,node[u].rm);

node[u].ma =
max (max (a,b),node[L(u)].rm + node[R(u)].lm);

}

void Build (int u,int left,int right)

{

node[u].l =
left;

node[u].r =
right;

node[u].len
= right - left + 1;

node[u].cover = -1;

if (left ==
right)

{

if (num[left])

{

node[u].sum = 1;

node[u].cover = 1;

node[u].lm = node[u].rm = node[u].ma = 1;

}

else

{

node[u].sum = 0;

node[u].cover = 0;

node[u].lm = node[u].rm = node[u].ma = 0;

}

return ;

}

int mid =
(left + right)>>1;

Build
(L(u),left,mid);

Build
(R(u),mid+1,right);

Union
(u);

}

void getdown (int
u)
//延迟操作,由父结点修改子结点

{
//也是常用手法

node[L(u)].cover = node[u].cover;

node[R(u)].cover = node[u].cover;

if
(node[u].cover)

{

node[L(u)].lm = node[L(u)].rm = node[L(u)].ma =
node[L(u)].len;

node[L(u)].sum = node[L(u)].len;

node[R(u)].lm = node[R(u)].rm = node[R(u)].ma =
node[R(u)].len;

node[R(u)].sum = node[R(u)].len;

}

else

{

node[L(u)].lm = node[L(u)].rm = node[L(u)].ma = 0;

node[L(u)].sum = 0;

node[R(u)].lm = node[R(u)].rm = node[R(u)].ma = 0;

node[R(u)].sum = 0;

}

node[u].cover = -1;

}

void Update1 (int u,int left,int right,int flag)
//下面这两个Update1,Update2 也算是经典了

{
//都是一个套路 左边,右边,或一起更新

if
(node[u].l == left &&node[u].r ==
right)

{

node[u].cover = flag;

if (flag)

{

node[u].lm = node[u].rm = node[u].ma = node[u].r - node[u].l +
1;

node[u].sum = node[u].ma;

}

else

{

node[u].lm = node[u].rm = node[u].ma = 0;

node[u].sum = 0;

}

return ;

}

if
(node[u].cover != -1)

getdown (u);

int mid =
(node[u].l + node[u].r)>>1;

if (right
<= mid)

Update1 (L(u),left,right,flag);

else if
(left >= mid + 1)

Update1(R(u),left,right,flag);

else

{

Update1(L(u),left,mid,flag);

Update1(R(u),mid+1,right,flag);

}

Union
(u);

}

void Update2 (int u,int left,int right)

{

if
(node[u].l == left&&node[u].r ==
right&&(node[u].sum ==
0||node[u].sum == node[u].len))

{

if (node[u].sum > 0)

{

node[u].lm = node[u].rm = node[u].ma = 0;

node[u].sum = 0;

node[u].cover = 0;

}

else

{

node[u].lm = node[u].rm = node[u].ma = node[u].len;

node[u].sum = node[u].len;

node[u].cover = 1;

}

return ;

}

if
(node[u].cover != -1)

getdown (u);

int mid =
(node[u].l + node[u].r)>>1;

if (right
<= mid)

Update2(L(u),left,right);

else if
(left >= mid + 1)

Update2(R(u),left,right);

else

{

Update2(L(u),left,mid);

Update2(R(u),mid + 1,right);

}

Union
(u);

}

int Query (int u,int left,int right,int flag) //查询操作
因为根据flag不同返回不同的值

{

if
(node[u].l == left &&node[u].r ==
right)

{

if (flag)

return node[u].ma;

else

return node[u].sum;

}

if
(node[u].cover != -1)

getdown (u);

int mid =
(node[u].l + node[u].r)>>1;

if (right
<= mid)

return Query(L(u),left,right,flag);

else if
(left >= mid + 1)

return Query(R(u),left,right,flag);

else
//这是的return得注意,当返回 连续1的个数时 注意中间断开的情况

{
//min (node[L(u)].rm,node[L(u)].r-left+1) 这是求左子结点右边最大的连续
右子结点同理

if (flag)

{

int a = max
(Query(L(u),left,mid,flag),Query(R(u),mid+1,right,flag));

return max (a,min (node[L(u)].rm,node[L(u)].r-left+1) + min
(node[R(u)].lm,right-node[R(u)].l + 1));

}

else

return (Query(L(u),left,mid,flag) +
Query(R(u),mid+1,right,flag));

}

}

int main ()

{

int
T,n,m,op,a,b;

scanf
("%d",&T);

while (T
--)

{

scanf ("%d%d",&n,&m);

for (int i = 1; i <= n; i ++)

scanf ("%d",&num[i]);

Build (1,1,n);

while (m --)

{

scanf
("%d%d%d",&op,&a,&b);

a ++,b++;

if (op == 0)

Update1(1,a,b,0);

else if (op == 1)

Update1 (1,a,b,1);

else if (op == 2)

Update2 (1,a,b);

else if (op == 3)

printf ("%d\n",Query (1,a,b,0)); //0 return sum;

else

printf ("%d\n",Query (1,a,b,1)); //1 return ma

}

}

return
0;

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