hdu 3397 Sequence operation (线段树 区间合并 多重标记)
Posted kls123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 3397 Sequence operation (线段树 区间合并 多重标记)相关的知识,希望对你有一定的参考价值。
链接;http://acm.hdu.edu.cn/showproblem.php?pid=3397
题意:
给你一串01串,有5种操作
0. 区间全部变为0
1.区间全部变为1
2.区间异或
3.询问区间1的个数
4.询问区间被最长连续1的长度
思路:
这5个操作都是比较基础的线段树操作,难点在于有两种修改操作,这类题之前也写过,之前是乘法和加法,这个是区间亦或和区间更新值,但是思路是可以借鉴的,我们要推出这两个操作的关系,这样才能维护好这两个标记,我们用两个标记:same , rev ,分别表示区间更新值和区间异或,那么向下更新的时候如果如果有same标记,清空当前区间的rev标记,简单维护下就好了,如果有rev标记,且有same标记,那么直接对same异或维护,如果没有same标记那么就维护下区间异或就好了。
写的超爽,一遍就a了,美滋滋,还以为又要找好久的错。。
实现代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define mid int m = (l + r) >> 1 #define ll long long const int M = 1e5 + 10; int lsum1[M<<2],rsum1[M<<2],sum1[M<<2]; int lsum0[M<<2],rsum0[M<<2],sum0[M<<2]; int sum[M<<2],same[M<<2],rev[M<<2]; int a[M]; void pushup(int l,int r,int rt){ mid; sum[rt] = sum[rt<<1] + sum[rt<<1|1]; lsum0[rt] = lsum0[rt<<1]; lsum1[rt] = lsum1[rt<<1]; rsum0[rt] = rsum0[rt<<1|1]; rsum1[rt] = rsum1[rt<<1|1]; if(lsum0[rt] == m-l+1) lsum0[rt] += lsum0[rt<<1|1]; if(rsum0[rt] == r-m) rsum0[rt] += rsum0[rt<<1]; if(lsum1[rt] == m-l+1) lsum1[rt] += lsum1[rt<<1|1]; if(rsum1[rt] == r-m) rsum1[rt] += rsum1[rt<<1]; sum0[rt] = max(max(sum0[rt<<1],sum0[rt<<1|1]),lsum0[rt<<1|1]+rsum0[rt<<1]); sum1[rt] = max(max(sum1[rt<<1],sum1[rt<<1|1]),lsum1[rt<<1|1]+rsum1[rt<<1]); } void swa(int len,int rt){ sum[rt] = len - sum[rt]; swap(lsum1[rt],lsum0[rt]); swap(rsum1[rt],rsum0[rt]); swap(sum1[rt],sum0[rt]); } void pushdown(int l,int r,int rt){ mid; if(same[rt]!=-1){ rev[rt<<1] = rev[rt<<1|1] = 0; same[rt<<1] = same[rt<<1|1] = same[rt]; if(same[rt]){ sum[rt<<1] = lsum1[rt<<1] = rsum1[rt<<1] = sum1[rt<<1] = m-l+1; sum[rt<<1|1] = lsum1[rt<<1|1] = rsum1[rt<<1|1] = sum1[rt<<1|1] = r-m; lsum0[rt<<1] = rsum0[rt<<1] = sum0[rt<<1] = sum0[rt<<1|1] = rsum0[rt<<1|1] = lsum0[rt<<1|1] = 0; } else{ sum[rt<<1] = lsum1[rt<<1] = rsum1[rt<<1] = sum1[rt<<1] = 0; sum[rt<<1|1] = lsum1[rt<<1|1] = rsum1[rt<<1|1] = sum1[rt<<1|1] = 0; lsum0[rt<<1] = rsum0[rt<<1] = sum0[rt<<1] = m-l+1; sum0[rt<<1|1] = rsum0[rt<<1|1] = lsum0[rt<<1|1] = r-m; } same[rt] = -1; } if(rev[rt]){ if(same[rt<<1] != -1){ same[rt<<1] ^= 1; if(same[rt<<1]){ sum[rt<<1] = lsum1[rt<<1] = rsum1[rt<<1] = sum1[rt<<1] = m-l+1; lsum0[rt<<1] = rsum0[rt<<1] = sum0[rt<<1] = 0; } else{ sum[rt<<1] = lsum1[rt<<1] = rsum1[rt<<1] = sum1[rt<<1] = 0; lsum0[rt<<1] = rsum0[rt<<1] = sum0[rt<<1] = m-l+1; } } else{ rev[rt<<1] ^= 1; swa(m-l+1,rt<<1); } if(same[rt<<1|1] != -1){ same[rt<<1|1] ^= 1; if(same[rt<<1|1]){ sum[rt<<1|1] = lsum1[rt<<1|1] = rsum1[rt<<1|1] = sum1[rt<<1|1] = r-m; sum0[rt<<1|1] = rsum0[rt<<1|1] = lsum0[rt<<1|1] = 0; } else{ sum[rt<<1|1] = lsum1[rt<<1|1] = rsum1[rt<<1|1] = sum1[rt<<1|1] = 0; sum0[rt<<1|1] = rsum0[rt<<1|1] = lsum0[rt<<1|1] = r-m; } } else{ rev[rt<<1|1] ^= 1; swa(r-m,rt<<1|1); } rev[rt] = 0; } } void build(int l,int r,int rt){ same[rt] = -1; rev[rt] = 0; lsum1[rt] = rsum1[rt] = lsum0[rt] = rsum0[rt] = sum0[rt] = sum1[rt] = sum[rt] = 0; if(l == r){ if(a[l]){ lsum1[rt] = sum[rt] = sum1[rt] = rsum1[rt] = 1; lsum0[rt] = rsum0[rt] = sum0[rt] = 0; } else { sum1[rt] = sum[rt] = sum1[rt] = rsum1[rt] = 0; lsum0[rt] = rsum0[rt] = sum0[rt] = 1; } return ; } mid ; build(lson); build(rson); pushup(l,r,rt); } void update_same(int L,int R,int c,int l,int r,int rt){ if(L <= l&&R >= r){ rev[rt] = 0; same[rt] = c; if(same[rt]){ sum[rt] = lsum1[rt] = rsum1[rt] = sum1[rt] = r-l+1; lsum0[rt] = rsum0[rt] = sum0[rt] = 0; } else{ sum[rt] = lsum1[rt] = rsum1[rt] = sum1[rt] = 0; lsum0[rt] = rsum0[rt] = sum0[rt] = r-l+1; } return ; } pushdown(l,r,rt); mid; if(L <= m) update_same(L,R,c,lson); if(R > m) update_same(L,R,c,rson); pushup(l,r,rt); } void update_rev(int L,int R,int l,int r,int rt){ if(L <= l&&R >= r){ if(same[rt] != -1){ same[rt] ^= 1; if(same[rt]){ sum[rt] = lsum1[rt] = rsum1[rt] = sum1[rt] = r-l+1; lsum0[rt] = rsum0[rt] = sum0[rt] = 0; } else{ sum[rt] = lsum1[rt] = rsum1[rt] = sum1[rt] = 0; lsum0[rt] = rsum0[rt] = sum0[rt] = r-l+1; } } else{ rev[rt] ^= 1; swa(r-l+1,rt); } return ; } mid ; pushdown(l,r,rt); if(L <= m) update_rev(L,R,lson); if(R > m) update_rev(L,R,rson); pushup(l,r,rt); } int query_sum(int L,int R,int l,int r,int rt){ if(L <= l&&R >= r){ return sum[rt]; } pushdown(l,r,rt); mid; int ret = 0; if(L <= m) ret += query_sum(L,R,lson); if(R > m) ret += query_sum(L,R,rson); return ret; } int query_max(int L,int R,int l,int r,int rt){ if(L <= l&&R >= r){ return sum1[rt]; } pushdown(l,r,rt); mid; int ret = 0; if(L > m) return query_max(L,R,rson); if(R <= m) return query_max(L,R,lson); int t1 = query_max(L,R,lson); int t2 = query_max(L,R,rson); int ls = min(rsum1[rt<<1],m-L+1); int rs = min(lsum1[rt<<1|1],R-m); return max(max(t1,t2),ls+rs); } int main() { int n,q,x,y,op,t; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&q); for(int i = 1;i <= n;i ++) scanf("%d",&a[i]); build(1,n,1); while(q--){ scanf("%d%d%d",&op,&x,&y); x++; y++; if(op == 0){ update_same(x,y,0,1,n,1); } else if(op == 1){ update_same(x,y,1,1,n,1); } else if(op == 2){ update_rev(x,y,1,n,1); } else if(op == 3){ printf("%d ",query_sum(x,y,1,n,1)); } else { printf("%d ",query_max(x,y,1,n,1)); } } } return 0; }
以上是关于hdu 3397 Sequence operation (线段树 区间合并 多重标记)的主要内容,如果未能解决你的问题,请参考以下文章
hdu-3397 Sequence operation 线段树多种标记
hdu 3397 Sequence operation (线段树 区间合并 多重标记)
HDU 3397 Sequence operation 多标记线段树