线段树+区间合并学习记录
学习了线段树的新姿势,记录一下。
参考blog:https://blog.csdn.net/sunyutian1998/article/details/79618316
HDU 1540:
query的时候m-ql+1和qr-m写成了m-l+1、r-m,wa了几发之后才找到bug。
错误样例:
10 1
Q 5
wrong answer:5
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=5e4+5; 4 struct node 5 { 6 int ll,rr,mm; 7 } tr[4*maxn]; 8 #define lson o*2 9 #define rson o*2+1 10 #define m (l+r)/2 11 inline void pushup(int o,int l,int r) 12 { 13 tr[o].ll=tr[lson].ll; 14 tr[o].rr=tr[rson].rr; 15 if(tr[o].ll==m-l+1) 16 tr[o].ll+=tr[rson].ll; 17 if(tr[o].rr==r-m) 18 tr[o].rr+=tr[lson].rr; 19 tr[o].mm=max(tr[lson].rr+tr[rson].ll,max(tr[lson].mm,tr[rson].mm)); 20 } 21 void build(int o,int l,int r) 22 { 23 if(l==r) 24 { 25 tr[o].ll=tr[o].rr=tr[o].mm=1; 26 return; 27 } 28 build(lson,l,m); 29 build(rson,m+1,r); 30 pushup(o,l,r); 31 } 32 void update(int o,int l,int r,int k,int flag) 33 { 34 if(l==r) 35 { 36 tr[o].ll=tr[o].rr=tr[o].mm=flag; 37 return; 38 } 39 if(k<=m) update(lson,l,m,k,flag); 40 else update(rson,m+1,r,k,flag); 41 pushup(o,l,r); 42 } 43 int query(int o,int l,int r,int ql,int qr,int flag) 44 { 45 if(ql<=l&&qr>=r) 46 { 47 if(flag==1) return tr[o].ll; 48 else return tr[o].rr; 49 } 50 if(qr<=m) return query(lson,l,m,ql,qr,flag); 51 if(ql>m) return query(rson,m+1,r,ql,qr,flag); 52 else 53 { 54 int pl=query(lson,l,m,ql,qr,flag); 55 int pr=query(rson,m+1,r,ql,qr,flag); 56 if(flag==1) 57 { 58 if(pl==m-ql+1) return pl+pr; 59 else return pl; 60 } 61 else 62 { 63 if(pr==qr-m) return pl+pr; 64 else return pr; 65 } 66 } 67 } 68 int a[maxn]; 69 int main() 70 { 71 int n,q; 72 while(scanf("%d%d",&n,&q)!=EOF) 73 { 74 memset(a,0,sizeof a); 75 build(1,1,n); 76 int tp=0; 77 while(q--) 78 { 79 char s; 80 getchar(); 81 scanf("%c",&s); 82 if(s=='D') 83 { 84 int x; 85 scanf("%d",&x); 86 update(1,1,n,x,0); 87 a[++tp]=x; 88 } 89 if(s=='Q') 90 { 91 int x; 92 scanf("%d",&x); 93 int x1=query(1,1,n,1,x,2); 94 int x2=query(1,1,n,x,n,1); 95 printf("%d\n",x1+x2>0?x1+x2-1:0); 96 } 97 if(s=='R') 98 { 99 if(tp>=1) 100 { 101 int x=a[tp--]; 102 update(1,1,n,x,1); 103 } 104 } 105 } 106 } 107 } 108 /* 109 10 1 110 Q 5 111 */
顺带一提,这个题目可以在set上面二分直接过,代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[50005]; 4 int main() 5 { 6 int n,q; 7 while(~scanf("%d%d",&n,&q)) 8 { 9 set<int>st; 10 st.insert(0); 11 int tp=0; 12 while(q--) 13 { 14 char c; 15 getchar(); 16 scanf("%c",&c); 17 if(c=='D') 18 { 19 int x; 20 scanf("%d",&x); 21 st.insert(x); 22 a[++tp]=x; 23 } 24 if(c=='Q') 25 { 26 int x; 27 scanf("%d",&x); 28 set<int>::iterator iter=st.lower_bound(x); 29 if(iter==st.end()) 30 { 31 iter--; 32 printf("%d\n",n-*iter); 33 } 34 else 35 { 36 if(*iter==x) puts("0"); 37 else 38 { 39 int tmp=*iter; 40 iter--; 41 printf("%d\n",tmp-*iter-1); 42 } 43 } 44 } 45 if(c=='R') 46 { 47 if(tp>=1) 48 { 49 int x=a[tp--]; 50 st.erase(x); 51 } 52 } 53 } 54 } 55 }
HDU 4553:
维护两棵线段树,一棵是空闲时间,一棵是无视基友的空闲时间,然后按区间合并的套路做就好了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=100005; 4 struct node 5 { 6 int ll,rr,mm; 7 int tag; 8 }ans0[4*maxn],ans1[4*maxn]; 9 #define lson o*2 10 #define rson o*2+1 11 #define m (l+r)/2 12 inline bool full(node tr[],int o,int l,int r) 13 { 14 return tr[o].mm==r-l+1; 15 } 16 inline void pushup(node tr[],int o,int l,int r) 17 { 18 tr[o].ll=tr[lson].ll; 19 tr[o].rr=tr[rson].rr; 20 if(tr[o].ll==m-l+1) 21 tr[o].ll+=tr[rson].ll; 22 if(tr[o].rr==r-m) 23 tr[o].rr+=tr[lson].rr; 24 tr[o].mm=max(tr[lson].rr+tr[rson].ll,max(tr[lson].mm,tr[rson].mm)); 25 } 26 inline void pushdown(node tr[],int o,int l,int r) 27 { 28 if(full(tr,o,l,r)) 29 { 30 tr[lson].ll=tr[lson].rr=tr[lson].mm=m-l+1; 31 tr[rson].ll=tr[rson].rr=tr[rson].mm=r-m; 32 } 33 if(tr[o].mm==0) 34 { 35 tr[lson].ll=tr[lson].rr=tr[lson].mm=0; 36 tr[rson].ll=tr[rson].rr=tr[rson].mm=0; 37 } 38 } 39 void build(node tr[],int o,int l,int r) 40 { 41 tr[o].tag=-1; 42 if(l==r) 43 { 44 tr[o].ll=tr[o].rr=tr[o].mm=1; 45 return; 46 } 47 build(tr,lson,l,m); 48 build(tr,rson,m+1,r); 49 pushup(tr,o,l,r); 50 } 51 void update(node tr[],int o,int l,int r,int ql,int qr,int flag) 52 { 53 if(ql<=l&&qr>=r) 54 { 55 tr[o].ll=tr[o].rr=tr[o].mm=flag*(r-l+1); 56 return; 57 } 58 pushdown(tr,o,l,r); 59 if(qr<=m) 60 update(tr,lson,l,m,ql,qr,flag); 61 else if(ql>m) 62 update(tr,rson,m+1,r,ql,qr,flag); 63 else 64 { 65 update(tr,lson,l,m,ql,qr,flag); 66 update(tr,rson,m+1,r,ql,qr,flag); 67 } 68 pushup(tr,o,l,r); 69 } 70 int query(node tr[],int o,int l,int r,int len) 71 { 72 if(tr[o].mm<len) 73 return -1; 74 pushdown(tr,o,l,r); 75 if(full(tr,o,l,r)) 76 return l; 77 if(tr[lson].mm>=len) 78 return query(tr,lson,l,m,len); 79 if(tr[lson].rr>0&&tr[lson].rr+tr[rson].ll>=len) 80 return m-tr[lson].rr+1; 81 if(tr[rson].mm>=len) 82 return query(tr,rson,m+1,r,len); 83 } 84 int main() 85 { 86 int t; 87 //freopen("in//in_t.txt","r",stdin); 88 //freopen("in//myout.txt","w",stdout); 89 scanf("%d",&t); 90 int cas=1; 91 while(t--) 92 { 93 printf("Case %d:\n",cas++); 94 int n,q; 95 scanf("%d%d",&n,&q); 96 build(ans0,1,1,n); 97 build(ans1,1,1,n); 98 while(q--) 99 { 100 char s[10]; 101 scanf("%s",s); 102 if(s[0]=='D') 103 { 104 int x; 105 scanf("%d",&x); 106 int pos=query(ans0,1,1,n,x); 107 if(pos==-1) puts("fly with yourself"); 108 else 109 { 110 printf("%d",pos); 111 puts(",let's fly"); 112 update(ans0,1,1,n,pos,pos+x-1,0); 113 } 114 } 115 if(s[0]=='N') 116 { 117 int x; 118 scanf("%d",&x); 119 int pos=query(ans0,1,1,n,x); 120 if(pos==-1) 121 { 122 pos=query(ans1,1,1,n,x); 123 if(pos==-1) puts("wait for me"); 124 else 125 { 126 printf("%d",pos); 127 puts(",don't put my gezi"); 128 update(ans0,1,1,n,pos,pos+x-1,0); 129 update(ans1,1,1,n,pos,pos+x-1,0); 130 } 131 } 132 else 133 { 134 printf("%d",pos); 135 puts(",don't put my gezi"); 136 update(ans0,1,1,n,pos,pos+x-1,0); 137 update(ans1,1,1,n,pos,pos+x-1,0); 138 } 139 } 140 if(s[0]=='S') 141 { 142 int l,r; 143 scanf("%d%d",&l,&r); 144 puts("I am the hope of chinese chengxuyuan!!"); 145 update(ans0,1,1,n,l,r,1); 146 update(ans1,1,1,n,l,r,1); 147 } 148 } 149 } 150 }
UVALive - 3938:
好像是道经典的线段树维护区间合并的题目。
动态查询区间连续最大和,输出那个最大和子区间的区间左端点和右端点,如果有多个子区间答案,输出l,r字典序最小的那一组。
线段树维护区间最大前缀和,后缀和,记录最大前缀和的结尾位置,最大后缀和的起点位置,以及最大子区间和的区间左右端点,至于区间求和,用前缀和sum[r]-sum[l-1]就好了。区间合并方式比较复杂,还是看代码吧:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 const LL maxn=500005; 5 typedef pair<LL,LL> P; 6 struct node 7 { 8 LL ll,rr; 9 P mxsub; 10 LL pre,post; 11 LL sum; 12 }tr[4*maxn]; 13 LL pre_sum[maxn]; 14 inline LL calc(LL l,LL r) 15 { 16 return pre_sum[r]-pre_sum[l-1]; 17 } 18 inline void comb(node& o,node& l,node& r) 19 { 20 o.sum=l.sum+r.sum; 21 if(l.ll>=l.sum+r.ll) 22 { 23 o.ll=l.ll; 24 o.pre=l.pre; 25 } 26 else 27 { 28 o.ll=l.sum+r.ll; 29 o.pre=r.pre; 30 } 31 if(r.rr>r.sum+l.rr) 32 { 33 o.rr=r.rr; 34 o.post=r.post; 35 } 36 else 37 { 38 o.rr=r.sum+l.rr; 39 o.post=l.post; 40 } 41 LL tmp1=calc(l.mxsub.first,l.mxsub.second); 42 LL tmp2=calc(r.mxsub.first,r.mxsub.second); 43 if(tmp1>=tmp2) 44 { 45 o.mxsub=l.mxsub; 46 if(tmp1<l.rr+r.ll) 47 { 48 o.mxsub.first=l.post; 49 o.mxsub.second=r.pre; 50 } 51 } 52 else 53 { 54 o.mxsub=r.mxsub; 55 if(tmp2<=l.rr+r.ll) 56 { 57 o.mxsub.first=l.post; 58 o.mxsub.second=r.pre; 59 } 60 } 61 } 62 LL a[maxn]; 63 #define lson o*2 64 #define rson o*2+1 65 #define m (l+r)/2 66 void build(LL o,LL l,LL r) 67 { 68 if(l==r) 69 { 70 tr[o].ll=tr[o].rr=tr[o].sum=a[l]; 71 tr[o].pre=tr[o].post=tr[o].mxsub.first=tr[o].mxsub.second=l; 72 return; 73 } 74 build(lson,l,m); 75 build(rson,m+1,r); 76 comb(tr[o],tr[lson],tr[rson]); 77 } 78 node query(LL o,LL l,LL r,LL ql,LL qr) 79 { 80 if(ql<=l&&qr>=r) 81 return tr[o]; 82 if(qr<=m) return query(lson,l,m,ql,qr); 83 if(ql>m) return query(rson,m+1,r,ql,qr); 84 node tmp1=query(lson,l,m,ql,qr); 85 node tmp2=query(rson,m+1,r,ql,qr); 86 node ret; 87 comb(ret,tmp1,tmp2); 88 return ret; 89 } 90 int main() 91 { 92 LL n; 93 LL cas=0; 94 while(~scanf("%lld",&n)) 95 { 96 printf("Case %lld:\n",++cas); 97 LL q; 98 scanf("%lld",&q); 99 for(LL i=1;i<=n;i++) 100 { 101 scanf("%lld",a+i); 102 pre_sum[i]=pre_sum[i-1]+a[i]; 103 } 104 build(1,1,n); 105 while(q--) 106 { 107 LL l,r; 108 scanf("%lld%lld",&l,&r); 109 node ans=query(1,1,n,l,r); 110 printf("%lld %lld\n",ans.mxsub.first,ans.mxsub.second); 111 } 112 } 113 }