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;
}
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;
}
相关文章推荐
- hdu 1854 Q-Sequence
- (HDU)1005 Number Sequence
- hdu 1854 Q-Sequence
- hdu 1806 Frequent values 线段…
- HDUACM 1297 Children’s Queue(递…
- hdu 1269 迷宫城堡&nbsp…
- HDU:2604 Queuing(发现似乎所有…
- HDU 1232 畅通工程
- HDU 3065 病毒侵袭持续中(AC自动…
- oracle&nbsp;浅见&nbsp;sequence
- 拓扑排序 hdu 2647 Reward
- hdu 1086
- hdu 1097 A hard puzzle
- HDU 2137 circumgyrate the string
- HDU 1977 Consecutive sum II
- HDU 1334 Perfect Cubes
- HDU&nbsp;4337&nbsp;King&nbsp;Arthur&#039;s&nbsp;Knights(…
- (HDU) 3999 The or…
- HDU:1015 Safecracker哈哈,这样…
- hdu 1026 简单的bfs