HDU 3397 Sequence operation(线段树区间合并)
题意:
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(线段树区间合并)相关推荐
- HDU - 3397 Sequence operation(线段树+区间合并)
题目链接:点击查看 题目大意:给定一个初始的数列,然后依次进行m次操作: 0 a b:将闭区间[a,b]内的点都变为0 1 a b:将闭区间[a,b]内的点都变为1 2 a b:将闭区间[a,b]内的 ...
- hdu 3397 Sequence operation(线段树,lazy,区间合并)
hdu 3397 Sequence operation 线段树lazy和区间合并结合的一个题,相当于几个题集中到一起嘛,分开想就好了 0,1,2操作都要lazy,2的异或操作找到每一只含1或只含0的区 ...
- HDU 3397 Sequence operation 线段树 成段更新 区间合并
比较综合的题. 两个标记 setv,xorr.setv的优先级高于xorr,当一个节点获得一个setv时,他之前的xorr要清除. //#pragma comment(linker, "/ ...
- HDU - 2871 Memory Control(线段树+区间合并)好题!
题目链接:点击查看 题目大意:给定n个内存和m个操作,分别是: New x:从内存编号1开始向右查找,分配一个长度为x的空间,若找到输出区间的首地址,否则输出Reject New: Free x:释放 ...
- HDU - 1540 Tunnel Warfare(线段树+区间合并)
题目链接:点击查看 题目大意:给定n个村庄,初始化全部连接为一条直线,需要依次执行m个操作,D表示摧毁第i个村庄的连接,R表示恢复最后一 个被摧毁的村庄的连接,Q表示询问包括本身在内,与第i个村庄相连 ...
- HDU 1540 Tunnel Warfare 线段树区间合并
Tunnel Warfare 题意:D代表破坏村庄,R代表修复最后被破坏的那个村庄,Q代表询问包括x在内的最大连续区间是多少 思路:一个节点的最大连续区间由(左儿子的最大的连续区间,右儿子的最大连续区 ...
- hdu 1540 Tunnel Warfare(线段树区间合并)
hdu 1540 Tunnel Warfare 记录每个节点的最大左连续值.最大右连续值.最大连续值,向上更新的是常规的区间合并处理方式 关键是想到如何去查询,如果查询节点落在左儿子节点的右连续段中, ...
- 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变 ...
- Tunnel Warfare(HDU1540+线段树+区间合并)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1540 题目: 题意:总共有n个村庄,有q次操作,每次操作分为摧毁一座村庄,修复一座村庄,和查询与询问的 ...
- HDU3308 线段树区间合并
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 ,简单的线段树区间合并. 线段树的区间合并:一般是要求求最长连续区间,在PushUp()函数中实 ...
最新文章
- 贷还是不贷:如何用Python和机器学习帮你决策?
- Spring Security 匿名认证
- Linux脚本关联,shell数组和关联数组
- MATLAB代写要求应该怎么写,matlab/simulink程序代写
- Spring点滴二:Spring Bean
- 如何解决UltraCompare中中文显示乱码的问题
- jwt重放攻击_【干货分享】基于JWT的Token认证机制及安全问题
- 开源FastGithub
- vue ts 设置tslint提示_Typescript在Vue中的实践
- 腾讯已问灵魂,鹅厂新立家风
- user32.dll 函数说明
- Eclipse的使用-Eclipse的简单使用,需要的来看看吧!
- python knn预测双色球_用KNN和回归分析进行预测(python)
- STM32F107单片机驱动Dp83848以太网芯片程序
- php 模板 {{}},PHP模板技术
- (转)《蜗居》带给校园男女多少悲喜
- 最大公约数用c语言表达,c语言求最大公约数(用c语言编写求最大公约数)
- centos7安装W3AF
- java user.dir 设置_关于user.dir的认识
- hdu2121 朱刘算法不定根