BZOJ 4592 SHOI2015 脑洞治疗仪 线段树
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4592
题意概述:
需要维护一个01序列A,一开始A全部都是1。支持如下操作:
1.将区间[l,r]变成0。
2.将区间[l0,r0]变成0,用其中原来1的个数去填补[l1,r1]中的0,当1的数量过多的时候剩余的1会被丢弃;当1的数量不足的时候从左到右依次填充0。
3.询问区间[l,r]中最长的0串长度。
N,M<=200000.
我就直接把考试的时候写的东西弄上来了:
首先建立一颗序列线段树,维护01序列,支持求和操作,同时维护最长序列。
对于1操作,直接区间赋值为0。
对于2操作,首先对[l0,r0]对1求和,记为x,然后赋值为0。然后在区间[l1,r1]中找到第一个0数量大于等于x的位置(实在没有就是r1),然后区间赋值。这一步可以用前缀和的思想,先求[1,l1-1](注意先对[l0,r0]操作)中的0数量y,然后就可以在线段树里直接查找第x+y个0的位置,最后的结果和r1比较,取较小值。
对于3操作,首先在线段树中维护区间左起最长、右起最长、区间最长的0串长度,查询的时候:要查询的区间完全在左半边或者右半边,直接递归处理;当查询区间跨越当前区间的中点,左右区间右起最长,左起最长各自与查询长度取min相加作为一个答案,递归到左右区间,三个答案取最大值;询问区间包含当前区间,直接返回区间最长0串长度(实际上处理的思路就是分治,跨越中间的,左边的,右边的)。
于是一通维护下来相当于要维护的东西有:1数量之和,0数量之和,0区间最长串三件套。
时间复杂度O(MlogN)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<set> 9 #include<map> 10 #include<vector> 11 #include<cctype> 12 using namespace std; 13 14 int N,M; 15 struct segment_tree{ 16 static const int maxn=400005; 17 int rt,np,lc[maxn],rc[maxn],s0[maxn],s1[maxn],ml[maxn],mr[maxn],mm[maxn],flag[maxn]; 18 segment_tree(){ rt=np=0; } 19 void pushup(int now,int L,int R){ 20 int m=L+R>>1; 21 s0[now]=s0[lc[now]]+s0[rc[now]]; 22 s1[now]=s1[lc[now]]+s1[rc[now]]; 23 ml[now]=max(ml[lc[now]],ml[lc[now]]==m-L+1?ml[lc[now]]+ml[rc[now]]:0); 24 mr[now]=max(mr[rc[now]],mr[rc[now]]==R-m?mr[rc[now]]+mr[lc[now]]:0); 25 mm[now]=max(mr[lc[now]]+ml[rc[now]],max(mm[lc[now]],mm[rc[now]])); 26 } 27 void pushdown(int now,int L,int R){ 28 if(flag[now]==-1) return; 29 int m=L+R>>1; 30 if(flag[now]==0){ 31 ml[lc[now]]=mr[lc[now]]=mm[lc[now]]=m-L+1; 32 s0[lc[now]]=m-L+1,s1[lc[now]]=0,flag[lc[now]]=0; 33 ml[rc[now]]=mr[rc[now]]=mm[rc[now]]=R-m; 34 s0[rc[now]]=R-m,s1[rc[now]]=0,flag[rc[now]]=0; 35 } 36 else{ 37 ml[lc[now]]=mr[lc[now]]=mm[lc[now]]=0; 38 s0[lc[now]]=0,s1[lc[now]]=m-L+1,flag[lc[now]]=1; 39 ml[rc[now]]=mr[rc[now]]=mm[rc[now]]=0; 40 s0[rc[now]]=0,s1[rc[now]]=R-m,flag[rc[now]]=1; 41 } 42 flag[now]=-1; 43 } 44 void build(int &now,int L,int R){ 45 now=++np; 46 lc[now]=rc[now]=0,s0[now]=ml[now]=mr[now]=mm[now]=0,s1[now]=R-L+1,flag[now]=-1; 47 if(L==R) return; 48 int m=L+R>>1; 49 build(lc[now],L,m); build(rc[now],m+1,R); 50 } 51 void update(int now,int L,int R,int A,int B,int v){ 52 if(A<=L&&R<=B){ 53 if(v==0){ 54 ml[now]=mr[now]=mm[now]=R-L+1; 55 s0[now]=R-L+1,s1[now]=0,flag[now]=0; 56 } 57 else{ 58 ml[now]=mr[now]=mm[now]=0; 59 s0[now]=0,s1[now]=R-L+1,flag[now]=1; 60 } 61 return; 62 } 63 pushdown(now,L,R); 64 int m=L+R>>1; 65 if(B<=m) update(lc[now],L,m,A,B,v); 66 else if(A>m) update(rc[now],m+1,R,A,B,v); 67 else update(lc[now],L,m,A,B,v),update(rc[now],m+1,R,A,B,v); 68 pushup(now,L,R); 69 } 70 int query_s(int now,int L,int R,int A,int B,int v){ 71 if(A<=L&&R<=B) return v?s1[now]:s0[now]; 72 pushdown(now,L,R); 73 int m=L+R>>1; 74 if(B<=m) return query_s(lc[now],L,m,A,B,v); 75 if(A>m) return query_s(rc[now],m+1,R,A,B,v); 76 return query_s(lc[now],L,m,A,B,v)+query_s(rc[now],m+1,R,A,B,v); 77 } 78 int query_p(int now,int L,int R,int k){ 79 if(L==R) return L; 80 pushdown(now,L,R); 81 int m=L+R>>1; 82 if(k<=s0[lc[now]]) return query_p(lc[now],L,m,k); 83 return query_p(rc[now],m+1,R,k-s0[lc[now]]); 84 } 85 int query_mm(int now,int L,int R,int A,int B){ 86 if(A<=L&&R<=B) return mm[now]; 87 pushdown(now,L,R); 88 int m=L+R>>1; 89 if(B<=m) return query_mm(lc[now],L,m,A,B); 90 if(A>m) return query_mm(rc[now],m+1,R,A,B); 91 int re=min(m-A+1,mr[lc[now]])+min(B-m,ml[rc[now]]); 92 return max(re,max(query_mm(lc[now],L,m,A,m),query_mm(rc[now],m+1,R,m+1,B))); 93 } 94 }st; 95 96 void work() 97 { 98 scanf("%d%d",&N,&M); 99 st.build(st.rt,1,N); 100 int op,l0,r0,l1,r1,x,y,p; 101 for(int i=1;i<=M;i++){ 102 scanf("%d",&op); 103 if(op==0){ 104 scanf("%d%d",&l0,%r0); 105 st.update(st.rt,1,N,l0,r0,0); 106 } 107 else if(op==1){ 108 scanf("%d%d%d%d",&l0,&r0,&l1,&r1); 109 x=st.query_s(st.rt,1,N,l0,r0,1); 110 if(!x) continue; 111 st.update(st.rt,1,N,l0,r0,0); 112 y=l1==1?0:st.query_s(st.rt,1,N,1,l1-1,0); 113 p=min(r1,st.query_p(st.rt,1,N,y+x)); 114 st.update(st.rt,1,N,l1,p,1); 115 } 116 else if(op==2){ 117 scanf("%d%d",&l0,&r0); 118 printf("%d\n",st.query_mm(st.rt,1,N,l0,r0)); 119 } 120 } 121 } 122 int main() 123 { 124 work(); 125 return 0; 126 }