1. 程式人生 > >hdu 3397 Sequence operation (線段樹 區間合並 多重標記)

hdu 3397 Sequence operation (線段樹 區間合並 多重標記)

pan 操作 bit clas 維護 最長 區間 acm can

鏈接;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\n",query_sum(x,y,1,n,1)); } else { printf("%d\n",query_max(x,y,1,n,1)); } } } return 0; }

hdu 3397 Sequence operation (線段樹 區間合並 多重標記)