題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1540
7 9 D 3 D 6 D 5 Q 4 Q 5 R Q 4 R Q 4
1 0 2 4
#include#include #include using namespace std; struct node { int l,r; int ls,rs,ms;//分別表示左邊最大連續,右邊最大連續,以及整個區間內的最大連續長度 } s[50050*3]; int n,m; int op[50010]; void InitTree(int l,int r,int k) { s[k].l=l; s[k].r=r; s[k].ls=s[k].rs=s[k].ms=r-l+1;//最開始的時候全都是連著的。所以長度為r-l+1 if (l==r) return ; int mid=(l+r)/2; InitTree(l,mid,k*2); InitTree(mid+1,r,k*2+1); } void UpdataTree(int x,int flag,int k)//x表示修復或者破壞的數字,flag用來標記是破壞還是修復 { if (s[k].l==s[k].r) { if (flag==1) s[k].ls=s[k].rs=s[k].ms=1;//修復 else s[k].ls=s[k].rs=s[k].ms=0;//破壞 return ; } int mid=(s[k].l+s[k].r)/2; if (x<=mid) UpdataTree(x,flag,2*k); else UpdataTree(x,flag,2*k+1); if(s[2*k].ls == s[2*k].r-s[2*k].l+1)//左區間的左連續=左子樹的長度,就說名左區間的數全部連續,(左子樹區間滿了),整個區間的左區間就應該加上有區間的左部分。 s[k].ls =s[2*k].ls+s[2*k+1].ls; else s[k].ls=s[2*k].ls; if(s[2*k+1].rs==s[2*k+1].r-s[2*k+1].l+1)//同理 s[k].rs=s[2*k+1].rs+s[2*k].rs; else s[k].rs=s[2*k+1].rs; s[k].ms=max(max(s[2*k].ms,s[2*k+1].ms),s[2*k].rs+s[2*k+1].ls);//整個區間內的最大連續應為:左子樹最大區間,右子樹最大區間,左右子樹合並的中間區間,三者中取最大 } int SearchTree(int x,int k) { if(s[k].l==s[k].r||s[k].ms==0||s[k].ms==s[k].r-s[k].l+1)//到了葉子節點或者該訪問區間為空或者已滿都不必要往下走了 return s[k].ms; int mid=(s[k].l+s[k].r)/2; if (x<=mid) { if (x>=s[2*k].r-s[2*k].rs+1)//判斷當前這個數是否在左區間的右連續中,其中s[2*k].r-s[2*k].rs+1代表左子樹右邊連續區間的左邊界值,即有連續區間的起點 return s[2*k].rs+s[2*k+1].ls;//也可以SearchTree(x,2*k)+SearchTree(mid+1,2*k+1); else return SearchTree(x,2*k); } else { if (x<=s[2*k+1].l+s[2*k+1].ls-1)//判斷當前這個數是否在左區間的右連續中,其中s[2*k].r-s[2*k].rs+1代表左子樹右邊連續區間的左邊界值,即有連續區間的起點 return s[2*k].rs+s[2*k+1].ls;//這種方法SearchTree(x,2*k+1)+SearchTree(mid,2*k);也是可以的,但是比較浪費時間 else return SearchTree(x,2*k+1); } } int main() { int x; char ch[2]; while (~scanf ("%d%d",&n,&m)) { int top=0; InitTree(1,n,1); while (m--) { scanf("%s",ch); if (ch[0]=='D') { scanf("%d",&x); op[top++]=x; UpdataTree(x,0,1); } else if (ch[0]=='Q') { scanf("%d",&x); printf ("%d\n",SearchTree(x,1)); } else { if (x>0) { x=op[--top]; UpdataTree(x,1,1); } } } } return 0; }