题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3397

题目大意:

0 a b表示a-b区间置为0

1 a b表示a-b区间置为1

2 a b表示a-b区间中的0变成1,1变成0

3 a b表示a-b区间中的1的数目

4 a b表示a-b区间中最长连续1的长度

解题思路:

线段树多种标记。

需要处理的东西比较多:

做题的时候发现一个问题:

我的宏定义Max不可以用于函数,尤其是递归函数,这样会使得同一函数重复调用好几遍,递归函数的话更会超时。

 #include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);//不可再使用scanf printf
#define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Mem(a) memset(a, 0, sizeof(a))
#define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1))
#define MID(l, r) ((l) + ((r) - (l)) / 2)
#define lson ((o)<<1)
#define rson ((o)<<1|1)
#pragma comment(linker, "/STACK:102400000,102400000")//栈外挂
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while (ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
} typedef long long ll;
const int maxn = + ;
const int MOD = ;//const引用更快,宏定义也更快 struct node
{
int l, r;//左右区间
int ls0, rs0, ms0;//左连续的0,右连续的0,区间最大连续的0
int ls1, rs1, ms1;//左连续的1,右连续的1,区间最大连续的1
int sum0, sum1;//区间0 1数目
int lazy, Xor;//懒惰标记和异或标记
}tree[maxn << ];
int a[maxn];
void pushup(int o)
{
if(tree[o].l == tree[o].r)return;//叶子节点直接返回
//根据子节点的信息,更新父节点信息 //更新0:
int lc = lson, rc = rson;
tree[o].ls0 = tree[lc].ls0;
tree[o].rs0 = tree[rc].rs0;
if(tree[lc].ls0 == tree[lc].r - tree[lc].l + )
tree[o].ls0 += tree[rc].ls0;//左节点左连续的0为区间长度 那么根节点左连续的0需要再加上右节点左连续的0
if(tree[rc].rs0 == tree[rc].r - tree[rc].l + )
tree[o].rs0 += tree[lc].rs0;
tree[o].ms0 = Max(Max(tree[lc].ms0, tree[rc].ms0), tree[lc].rs0 + tree[rc].ls0);//最大连续0 = Max(左节点最大连续0, 右节点最大连续0,中间最大连续0)
tree[o].sum0 = tree[lc].sum0 + tree[rc].sum0;
//更新1
tree[o].ls1 = tree[lc].ls1;
tree[o].rs1 = tree[rc].rs1;
if(tree[lc].ls1 == tree[lc].r - tree[lc].l + )
tree[o].ls1 += tree[rc].ls1;//左节点左连续的0为区间长度 那么根节点左连续的0需要再加上右节点左连续的0
if(tree[rc].rs1 == tree[rc].r - tree[rc].l + )
tree[o].rs1 += tree[lc].rs1;
tree[o].ms1 = Max(Max(tree[lc].ms1, tree[rc].ms1), tree[lc].rs1 + tree[rc].ls1);//最大连续0 = Max(左节点最大连续0, 右节点最大连续0,中间最大连续0)
tree[o].sum1 = tree[lc].sum1 + tree[rc].sum1;
}
void XOR(int o)
{
swap(tree[o].ls0, tree[o].ls1);
swap(tree[o].rs0, tree[o].rs1);
swap(tree[o].ms0, tree[o].ms1);
swap(tree[o].sum0, tree[o].sum1);
}
void pushdown(int o)//标记下传
{
if(tree[o].l == tree[o].r)return;
if(tree[o].lazy != -)//区间覆盖0或者1
{
int lc = lson, rc = rson, len = tree[o].r - tree[o].l + ;
tree[lc].lazy = tree[rc].lazy = tree[o].lazy;
tree[lc].Xor = tree[rc].Xor = ; //左节点长度为(len+1) / 2 右节点长度为len/2
//左
tree[lc].ls0 = tree[lc].rs0 = tree[lc].ms0 = tree[o].lazy ? : (len + ) / ;
tree[lc].ls1 = tree[lc].rs1 = tree[lc].ms1 = tree[o].lazy ? (len + ) / : ;
tree[lc].sum0 = tree[o].lazy ? : (len + ) / ;
tree[lc].sum1 = tree[o].lazy ? (len + ) / : ;
//右
tree[rc].ls0 = tree[rc].rs0 = tree[rc].ms0 = tree[o].lazy ? : (len) / ;
tree[rc].ls1 = tree[rc].rs1 = tree[rc].ms1 = tree[o].lazy ? (len) / : ;
tree[rc].sum0 = tree[o].lazy ? : (len) / ;
tree[rc].sum1 = tree[o].lazy ? (len) / : ; tree[o].lazy = -;//清除标记
}
if(tree[o].Xor)
{
tree[o].Xor = ;
tree[lson].Xor ^= ;
tree[rson].Xor ^= ;
XOR(lson), XOR(rson);
}
}
void build(int o, int l, int r)
{
tree[o].l = l, tree[o].r = r, tree[o].lazy = -, tree[o].Xor = ;
if(l == r)
{
tree[o].ls0 = tree[o].rs0 = tree[o].ms0 = (a[l] == );
tree[o].ls1 = tree[o].rs1 = tree[o].ms1 = (a[l] == );
tree[o].sum1 = (a[l] == );
tree[o].sum0 = (a[l] == );
return;
}
int m = MID(l, r);
build(lson, l, m);
build(rson, m + , r);
pushup(o);
}
int flag;//标记类型
int ql, qr;
void update(int o)
{
pushdown(o);
if(ql <= tree[o].l && qr >= tree[o].r)
{
if(flag == )
{
tree[o].Xor = ;
XOR(o);
}
else
{
int len = tree[o].r - tree[o].l + ;
tree[o].lazy = flag;
tree[o].ls0 = tree[o].rs0 = tree[o].ms0 = flag ? : len;
tree[o].ls1 = tree[o].rs1 = tree[o].ms1 = flag ? len : ;
tree[o].sum0 = flag ? : len;
tree[o].sum1 = flag ? len : ;
}
}
else
{
int m = MID(tree[o].l, tree[o].r);
if(ql <= m)update(lson);
if(qr > m)update(rson);
pushup(o);
}
} int query(int o)
{
pushdown(o);
if(ql <= tree[o].l && qr >= tree[o].r)
{
if(flag == )return tree[o].sum1;
else return tree[o].ms1;
}
else
{
if(qr <= tree[lson].r)return query(lson);
if(ql >= tree[rson].l)return query(rson);
if(flag == )return query(lson) + query(rson);
int ans1 = Min(tree[lson].rs1, tree[lson].r - ql + ) + Min(tree[rson].ls1, qr - tree[rson].l + );
int ans2 = max(query(lson), query(rson));//用宏定义会超时,因为一直在递归
return Max(ans1, ans2);
}
} int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n, m;
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++)scanf("%d", &a[i]);
build(, , n);
while(m--)
{
scanf("%d%d%d", &flag, &ql, &qr);
ql++, qr++;
if(flag < )update();
else printf("%d\n", query());
}
}
return ;
}

hdu-3397 Sequence operation 线段树多种标记的更多相关文章

  1. hdu 3397 Sequence operation (线段树 区间合并 多重标记)

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意: 给你一串01串,有5种操作 0. 区间全部变为0 1.区间全部变为1 2.区间异或 3.询问 ...

  2. hdu 3397 Sequence operation 线段树

    题目链接 给出n个数, 每个数是0或1, 给5种操作, 区间变为1, 区间变为0, 区间0,1翻转, 询问区间内1的个数, 询问区间内最长连续1的个数. 需要将数组开成二维的, 然后区间0, 1翻转只 ...

  3. hdu 3397 Sequence operation 线段树 区间更新 区间合并

    题意: 5种操作,所有数字都为0或1 0 a b:将[a,b]置0 1 a b:将[a,b]置1 2 a b:[a,b]中的0和1互换 3 a b:查询[a,b]中的1的数量 4 a b:查询[a,b ...

  4. HDU 3397 Sequence operation(线段树)

    HDU 3397 Sequence operation 题目链接 题意:给定一个01序列,有5种操作 0 a b [a.b]区间置为0 1 a b [a,b]区间置为1 2 a b [a,b]区间0变 ...

  5. hdu 3397 Sequence operation(线段树:区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意:给你一个长度为n的0,1序列,支持下列五种操作, 操作0(0 a b):将a到b这个区间的 ...

  6. hdu 3397 Sequence operation(很有意思的线段树题)

    Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  7. 【线段树】HDU 3397 Sequence operation 区间合并

    操作 Change operations: 0 a b change all characters into '0's in [a , b] 1 a b change all characters i ...

  8. Sequence operation(线段树区间多种操作)

    Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  9. hdu3397 Sequence operation 线段树

    hdu3397 Sequence operation #include <bits/stdc++.h> using namespace std; ; struct node { /// l ...

随机推荐

  1. SQL Serever学习11——数据库的安全管理

    公司管理软件设计完成,但是日常工作繁忙,向领导提出增加几个管理员,帮助管理和维护系统,领导同意了,但是要求一定要管理好这几个管理员用户,保证数据库的安全. 修改身份验证模式 数据库验证机制 sqlse ...

  2. 【原】Ajax技术原理

    主要内容: Ajax原理 Ajax核心技术 Ajax是Asynchronous JavaScript and XML的简称,意思是异步的JavaScript和XML. 主要包括技术: web标准的XH ...

  3. c#参数修饰符-params

    先来理解一下理论知识 params可以设置使用长度可变的参数. 使用要求: 1.在一个方法声明的参数中,只能有一个params修饰符,且被修饰的参数之后不能有其他参数(这一点就像“可选参数必须在必选参 ...

  4. AJAX同步问题

    @using ShippingRen.CommonV2.CloudStorage; @using ShippingRen.Api.ServiceModel.PublicDataEntity.Looku ...

  5. android 使用图片轮播图---banner 使用

    转自:https://github.com/youth5201314/banner 使用步骤 Step 1.依赖banner Gradle dependencies{ compile 'com.you ...

  6. java常见异常(转载)

    版权声明: https://blog.csdn.net/qq_32595075/article/details/80059834 一般面试中java Exception(runtimeExceptio ...

  7. 撩课-Python-每天5道面试题-第7天

    一. 函数的返回值的概念,语法以及注意事项? 场景 当我们通过某个函数, 处理好数据之后, 想要拿到处理的结果 语法 def 函数(): 函数体 return 数据 注意事项 3.1 return 后 ...

  8. 【SSH网上商城项目实战19】订单信息的级联入库以及页面的缓存问题

          转自: https://blog.csdn.net/eson_15/article/details/51433247 购物车这一块还剩最后两个问题,就是订单信息的级联入库和页面缓存,这里的 ...

  9. JSP简单实现登录和注销

    JSP简单实现登录和注销 需求:用户登录成功后跳转到欢迎页面 用户登录失败跳转到初始的登录界面 用户点击注销,用户退出登录状态需要重新登录 登录页面的JSP代码: <%@ page langua ...

  10. DOM基础操作(三)

    DOM剩余的两个操作一并带来! 1.删除操作 removeChild 这个方法依然是父级调用的,参数就是要删除的子节点,其实实际上是剪切,这个方法会把我们删除掉的元素给返回,我们可以用一个变量去保存这 ...