HDU1540 Tunnel Warfare(线段树:维护最大连续子串)
http://acm.hdu.edu.cn/showproblem.php?pid=1540
分析:
首先先来分析题目中的3种操作:
1.D x: 该操作就是单点更新
2.Q x: 该操作可以分解为查区间[1,x]的最大连续0后缀长L和区间[x,n]的最大连续0前缀长R,则R+L-1即为所求.有关前缀查询和后缀查询可以参考:
http://blog.csdn.net/u013480600/article/details/22421981
3.R : 该操作其实就是update,不过需要一个stack来保存以前D过的点.
维护一棵线段树,该树的每个节点维护的信息为:
cover:-1,0或1,分别表示多重信息,未被摧毁,被摧毁
pre: 表示当前节点的最大连续0的前缀长度
suf: 表示当前节点的最大连续0的后缀长度
线段树的基本操作.
1. PushUp(i,l,r):根据子节点的信息更新父节点的cover,suf,pre信息
2. PushDown(i,l,r):如果cover位!=-1,则更新子树的3类信息
3. build(i,l,r):建树
如果l==r,单独处理并返回.
否则先PushDown;
递归建立左右子树
PushUp
4. update(p,v,i,l,r):将p位置的cover值置为v.
如果l==r,那么直接更新信息并返回.
否则先PushDown.
如果p<=m,就update左子树
否则update 右子树
最后PushUp
5. query_pre(ql,qr,i,l,r):查询[ql,qr]与[l,r]区间公共部分的最长前缀连续0长度.
if(ql<=l && r<=qr) 直接返回 pre[i]
PushDown
如果[ql,qr]只与[l,r]的左子树相关,就return query_pre(lson)
如果[ql,qr]只与[l,r]的右子树相关,就return query_pre(rson)
左右子树都相关,则令L= query_pre(lson),如果L==m-max(ql,l)+1
,那么就令L+=query_pre(rson)
返回L
6. query_suf(ql,qr,i,l,r):查询[ql,qr]与[l,r]区间公共部分的最长后缀连续0长度.
if(ql<=l && r<=qr) 直接返回 suf[i]
PushDown
如果[ql,qr]只与[l,r]的左子树相关,就return query_suf(lson)
如果[ql,qr]只与[l,r]的右子树相关,就return query_suf(rson)
左右子树都相关,则令R= query_suf(rson),如果R==min(qr,r)-m
,那么就令R+=query_suf(lson)
返回L
AC代码:453ms,一次编译通过并AC
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<stack> using namespace std; const int MAXN=50000+1000; #define lson i*2,l,m #define rson i*2+1,m+1,r #define root 1,1,n int cover[MAXN*4],pre[MAXN*4],suf[MAXN*4]; void PushUp(int i,int l,int r) { int m=(l+r)/2; //cover if(cover[i*2]==-1 || cover[i*2+1]==-1) cover[i]=-1; else if(cover[i*2] != cover[i*2+1]) cover[i]=-1; else cover[i]=cover[i*2]; //pre pre[i]=pre[i*2]; if(pre[i]== m-l+1)pre[i] +=pre[i*2+1]; //suf suf[i]=suf[i*2+1]; if(suf[i]==r-m) suf[i]+=suf[i*2]; } void PushDown(int i,int l,int r) { int m=(l+r)/2; if(cover[i]!=-1) { cover[i*2]=cover[i*2+1]=cover[i]; suf[i*2]=pre[i*2]= (cover[i]?0:m-l+1); suf[i*2+1]=pre[i*2+1]= (cover[i]?0:r-m); } } void build(int i,int l,int r) { if(l==r) { cover[i]=0; suf[i]=pre[i]=1; return ; } int m=(l+r)/2; build(lson); build(rson); PushUp(i,l,r); } void update(int p,int v,int i,int l,int r) { if(l==r) { cover[i]=v; suf[i]=pre[i]= (v?0:1); return ; } PushDown(i,l,r); int m=(l+r)/2; if(p<=m) update(p,v,lson); else update(p,v,rson); PushUp(i,l,r); } int query_pre(int ql,int qr,int i,int l,int r)//查找[ql,qr]与[l,r]的公共部分的最大前缀连续0的长度 { if(ql<=l && r<=qr) return pre[i]; PushDown(i,l,r); int m=(l+r)/2; if(qr<=m) return query_pre(ql,qr,lson); if(m<ql) return query_pre(ql,qr,rson); int L = query_pre(ql,qr,lson); if(L == m+1-max(l,ql) ) L +=query_pre(ql,qr,rson); return L; } int query_suf(int ql,int qr,int i,int l,int r)//查找[ql,qr]与[l,r]的公共部分的最大后缀连续0的长度 { if(ql<=l && r<=qr) return suf[i]; PushDown(i,l,r); int m=(l+r)/2; if(qr<=m) return query_suf(ql,qr,lson); if(m<ql) return query_suf(ql,qr,rson); int R = query_suf(ql,qr,rson); if(R == min(r,qr)-m ) R +=query_suf(ql,qr,lson); return R; } int main() { int n,m; while(scanf("%d%d",&n,&m)==2) { build(root); stack<int> sq; while(m--) { char str[10]; int x; scanf("%s",str); if(str[0]=='D') { scanf("%d",&x); sq.push(x); update(x,1,root); } else if(str[0]=='Q') { scanf("%d",&x); int L=query_suf(1,x,root); int R=query_pre(x,n,root); if(L==0) printf("0\n"); else printf("%d\n",L+R-1); } else if(str[0]=='R') { if(!sq.empty()) { int x= sq.top();sq.pop(); update(x,0,root); } } } } return 0; }