题意:

0 a b将区间[a,b]所有数全部变成0
1 a b将区间[a,b]所有数全部变成1
2 a b将区间[a,b]中所有数0 1互换,0变1,1变0
3 a b输出区间[a,b]中1的个数
4 a b输出区间[a,b]中最长连续1的个数

解析:

涉及到线段树的多种操作。
mxL[0]表示左边最长连续0的个数
mxR[0]表示右边最长连续0的个数
mx[0]表示当前区间最长连续0的个数
mxL[1],mxR[1],mx[1]同上
为什么要定义mx[0],和mx[1]这些标记,是为了在区间翻转的时候得到互相的值。

查询区间最长连续1个数的过程中;
maxl=[l,m]上最长连续1个数maxl=[l,m]上最长连续1个数
maxl=[m+1,r]上最长连续1的个数maxl=[m+1,r]上最长连续1的个数
maxm=min(m−l+1,左孩子的rs)+min(r−m,右孩子的ls)maxm=min(m-l+1,左孩子的rs)+min(r-m,右孩子的ls)
结果应该是这三个中的最大值,即max(maxl,maxr,maxm)max(maxl,maxr,maxm)

注意:

有个地方需要注意下,就是懒惰传递的先后问题。
我一直WA在这里,后看别人解释,如果覆盖的话,那么异或已经没有用了,把异或标记为0即可。

还有一个问题,怎么确定是先覆盖再异或,还是先异或再覆盖。
这两个的结果可能是不同的,所以必须确定,是怎么的一种传递方法?

传递的时候,如果是覆盖传递,那么子节点的异或失效。如果是异或传递,无影响。(因为存在异或,说明之前不会有覆盖经过这里)

mymy codecode

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
using namespace std;
const int N = 1e5 + 10;int n, m;
int mxL[N<<2][2], mxR[N<<2][2], mx[N<<2][2];
int sum[N<<2];
int XOR[N<<2], cov[N<<2];inline int max(int a, int b, int c) { return max(a, max(b, c)); }void setXOR(int o, int L, int R) {XOR[o] ^= 1;swap(mxL[o][0], mxL[o][1]);swap(mxR[o][0], mxR[o][1]);swap(mx[o][0], mx[o][1]);sum[o] = (R - L + 1) - sum[o];
}void setCov(int o, int L, int R) {int cur = cov[o], tmp = cov[o]^1;int len = R - L + 1;mxL[o][cur] = mxR[o][cur] = mx[o][cur] = len;mxL[o][tmp] = mxR[o][tmp] = mx[o][tmp] = 0;sum[o] = cur * len;
}void pushDown(int o, int L, int R) {int M = (L + R)/2;if(cov[o] != -1) {cov[ls] = cov[rs] = cov[o];XOR[ls] = XOR[rs] = false;setCov(lson);setCov(rson);cov[o] = -1;}if(XOR[o]) {setXOR(lson);setXOR(rson);XOR[o] = false;}
}void merge(int o, int L, int R, int x) {int M = (L + R)/2;mxL[o][x] = mxL[ls][x]; mxR[o][x] = mxR[rs][x];int len1 = M - L + 1, len2 = R - M;if(mxL[ls][x] == len1) mxL[o][x] += mxL[rs][x];if(mxR[rs][x] == len2) mxR[o][x] += mxR[ls][x];int midlen = mxR[ls][x] + mxL[rs][x];mx[o][x] = max(mx[ls][x], mx[rs][x], midlen);
}void pushUp(int o, int L, int R) {merge(o, L, R, 1);merge(o, L, R, 0);sum[o] = sum[ls] + sum[rs];
}void modify(int o, int L, int R, int ql, int qr, int op) {if(ql <= L && R <= qr) {if(op < 2) {cov[o] = op;XOR[o] = false;setCov(o, L, R);}else {setXOR(o, L, R);}return ;}pushDown(o, L, R);int M = (L + R)/2;if(ql <= M) modify(lson, ql, qr, op);if(qr > M) modify(rson, ql, qr, op);pushUp(o, L, R);
}int queryMax(int o, int L, int R, int ql, int qr) {if(ql <= L && R <= qr) return mx[o][1];int M = (L + R)/2, ret = 0;pushDown(o, L, R);if(qr <= M) ret = queryMax(lson, ql, qr);else if(ql > M) ret = queryMax(rson, ql, qr);else {int len1 = queryMax(lson, ql, M), len2 = queryMax(rson, M+1, qr);  int len0 = min(mxR[ls][1], (M - ql + 1)) + min(mxL[rs][1], (qr - M));ret = max(len0, len1, len2);}pushUp(o, L, R);return ret;
}int querySum(int o, int L, int R, int ql, int qr) {if(ql <= L && R <= qr) return sum[o];int M = (L + R)/2, ret = 0;pushDown(o, L, R);if(ql <= M) ret += querySum(lson, ql, qr);if(qr > M) ret += querySum(rson, ql, qr);pushUp(o, L, R);return ret;
}void build(int o, int L, int R) {cov[o] = -1, XOR[o] = false;if(L == R) {int val;scanf("%d", &val);cov[o] = val;setCov(o, L, R);return ;}int M = (L + R)/2;build(lson);build(rson);pushUp(o, L, R);
}int main() {int op, a, b;int T;scanf("%d", &T);while(T--) {scanf("%d%d", &n, &m);build(1, 0, n-1);while(m--) {scanf("%d%d%d", &op, &a, &b);if(op <= 2) {modify(1, 0, n-1, a, b, op);}else if(op == 3) {printf("%d\n", querySum(1, 0, n-1, a, b));}else {printf("%d\n", queryMax(1, 0, n-1, a, b));}}}return 0;
}

HDU 3397 Sequence operation(线段树区间合并)相关推荐

  1. HDU - 3397 Sequence operation(线段树+区间合并)

    题目链接:点击查看 题目大意:给定一个初始的数列,然后依次进行m次操作: 0 a b:将闭区间[a,b]内的点都变为0 1 a b:将闭区间[a,b]内的点都变为1 2 a b:将闭区间[a,b]内的 ...

  2. hdu 3397 Sequence operation(线段树,lazy,区间合并)

    hdu 3397 Sequence operation 线段树lazy和区间合并结合的一个题,相当于几个题集中到一起嘛,分开想就好了 0,1,2操作都要lazy,2的异或操作找到每一只含1或只含0的区 ...

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

    比较综合的题. 两个标记  setv,xorr.setv的优先级高于xorr,当一个节点获得一个setv时,他之前的xorr要清除. //#pragma comment(linker, "/ ...

  4. HDU - 2871 Memory Control(线段树+区间合并)好题!

    题目链接:点击查看 题目大意:给定n个内存和m个操作,分别是: New x:从内存编号1开始向右查找,分配一个长度为x的空间,若找到输出区间的首地址,否则输出Reject New: Free x:释放 ...

  5. HDU - 1540 Tunnel Warfare(线段树+区间合并)

    题目链接:点击查看 题目大意:给定n个村庄,初始化全部连接为一条直线,需要依次执行m个操作,D表示摧毁第i个村庄的连接,R表示恢复最后一 个被摧毁的村庄的连接,Q表示询问包括本身在内,与第i个村庄相连 ...

  6. HDU 1540 Tunnel Warfare 线段树区间合并

    Tunnel Warfare 题意:D代表破坏村庄,R代表修复最后被破坏的那个村庄,Q代表询问包括x在内的最大连续区间是多少 思路:一个节点的最大连续区间由(左儿子的最大的连续区间,右儿子的最大连续区 ...

  7. hdu 1540 Tunnel Warfare(线段树区间合并)

    hdu 1540 Tunnel Warfare 记录每个节点的最大左连续值.最大右连续值.最大连续值,向上更新的是常规的区间合并处理方式 关键是想到如何去查询,如果查询节点落在左儿子节点的右连续段中, ...

  8. 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变 ...

  9. Tunnel Warfare(HDU1540+线段树+区间合并)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1540 题目: 题意:总共有n个村庄,有q次操作,每次操作分为摧毁一座村庄,修复一座村庄,和查询与询问的 ...

  10. HDU3308 线段树区间合并

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 ,简单的线段树区间合并. 线段树的区间合并:一般是要求求最长连续区间,在PushUp()函数中实 ...

最新文章

  1. 贷还是不贷:如何用Python和机器学习帮你决策?
  2. Spring Security 匿名认证
  3. Linux脚本关联,shell数组和关联数组
  4. MATLAB代写要求应该怎么写,matlab/simulink程序代写
  5. Spring点滴二:Spring Bean
  6. 如何解决UltraCompare中中文显示乱码的问题
  7. jwt重放攻击_【干货分享】基于JWT的Token认证机制及安全问题
  8. 开源FastGithub
  9. vue ts 设置tslint提示_Typescript在Vue中的实践
  10. 腾讯已问灵魂,鹅厂新立家风
  11. user32.dll 函数说明
  12. Eclipse的使用-Eclipse的简单使用,需要的来看看吧!
  13. python knn预测双色球_用KNN和回归分析进行预测(python)
  14. STM32F107单片机驱动Dp83848以太网芯片程序
  15. php 模板 {{}},PHP模板技术
  16. (转)《蜗居》带给校园男女多少悲喜
  17. 最大公约数用c语言表达,c语言求最大公约数(用c语言编写求最大公约数)
  18. centos7安装W3AF
  19. java user.dir 设置_关于user.dir的认识
  20. hdu2121 朱刘算法不定根

热门文章

  1. 数据结构3-栈的知识点整理
  2. 隐私政策网址 (URL)
  3. 华农计算机科学转专业,转专业门槛有多高? 每8名新生就有一个想转专业
  4. mysql 查看slave状态_解读show slave status 命令判断MySQL复制同步状态
  5. 小强升职记:时间管理故事书
  6. MySQL备份和还原操作
  7. MySql-主从复制
  8. Python Module — OpenAI ChatGPT API
  9. C++的封装、继承和多态
  10. SpringBoot:Sa-Token的具体介绍与使用