標籤:hdu 1540 poj 2892 tunnel warfare 線段樹 區間合并
~~~~
第一次遇到線段樹合并的題,又被律爺教做人。TAT.
~~~~
線段樹的題意都很好理解吧。。
題目連結:
http://acm.hdu.edu.cn/showproblem.php?pid=1540
http://poj.org/problem?id=2892
~~~~
My Code:200ms
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define N 55555#define lson rt<<1,s,m#define rson rt<<1|1,m+1,eusing namespace std;int st[N];struct node{ int l,r; int lm,rm; //維護一個區間從左右端點開始的最長區間}tre[N<<2];void build(int rt,int s,int e){ tre[rt].l=s; tre[rt].r=e; tre[rt].lm=tre[rt].rm=e-s+1; if(s==e) return ; int m=(s+e)>>1; build(lson); build(rson);}void update(int p,int v,int rt,int s,int e){ if(s==e) { if(v) tre[rt].lm=tre[rt].rm=1; //rebuild else tre[rt].lm=tre[rt].rm=0; //destroy return ; } int m=(s+e)>>1; if(p<=m) update(p,v,lson); else update(p,v,rson); tre[rt].lm=tre[rt<<1].lm; tre[rt].rm=tre[rt<<1|1].rm; //若lm==區間長,還要加上右孩子的lm。 if(tre[rt<<1].lm==tre[rt<<1].r-tre[rt<<1].l+1) tre[rt].lm=tre[rt<<1].lm+tre[rt<<1|1].lm; if(tre[rt<<1|1].rm==tre[rt<<1|1].r-tre[rt<<1|1].l+1) //同理~ tre[rt].rm=tre[rt<<1|1].rm+tre[rt<<1].rm;}int query(int q,int rt,int s,int e){ //總是把查詢操作歸結到一個父親節點下的兩個孩子節點的中間地區的最長連續區間。 if(s==e) return tre[rt].lm; int m=(s+e)>>1; int l=m-tre[rt<<1].rm; int r=m+1+tre[rt<<1|1].lm; if(q>l && q<r) //要尋找的端點就在該區間的連續區間中,則返回。 return tre[rt<<1].rm+tre[rt<<1|1].lm; else if(q<=l) query(q,lson); else query(q,rson);}int main(){ int n,m; while(~scanf("%d%d",&n,&m)) { int top=-1; build(1,1,n); for(int i=0;i<m;i++) { int x; char str[5]; scanf("%s",str); if(str[0]=='D') { scanf("%d",&x); update(x,0,1,1,n); st[++top]=x; } else if(str[0]=='R') { int y=st[top--]; if(top>=-1) update(y,1,1,1,n); } else if(str[0]=='Q') { scanf("%d",&x); int k=query(x,1,1,n); printf("%d\n",k); } } } return 0;}
~~~~
之前參考網上代碼所寫:300ms;
#include<cstdio>#include<cstring>#include<algorithm>#define N 55555#define lson rt<<1,s,m#define rson rt<<1|1,m+1,eusing namespace std;int st[N];struct node{ int l,r; int lm,rm,sm; //還要維護一個區間的最長連續區間}tre[N<<2];void build(int rt,int s,int e){ tre[rt].l=s; tre[rt].r=e; tre[rt].lm=tre[rt].rm=tre[rt].sm=e-s+1; if(s==e) return ; int m=(s+e)>>1; build(lson); build(rson);}void update(int p,int v,int rt,int s,int e){ if(s==e) { if(v) tre[rt].lm=tre[rt].rm=tre[rt].sm=1; else tre[rt].lm=tre[rt].rm=tre[rt].sm=0; return ; } int m=(s+e)>>1; if(p<=m) update(p,v,lson); else update(p,v,rson); tre[rt].lm=tre[rt<<1].lm; tre[rt].rm=tre[rt<<1|1].rm; tre[rt].sm=max(max(tre[rt<<1].sm,tre[rt<<1|1].sm),tre[rt<<1].rm+tre[rt<<1|1].lm); if(tre[rt<<1].lm==tre[rt<<1].r-tre[rt<<1].l+1) tre[rt].lm=tre[rt<<1].lm+tre[rt<<1|1].lm; if(tre[rt<<1|1].rm==tre[rt<<1|1].r-tre[rt<<1|1].l+1) tre[rt].rm=tre[rt<<1|1].rm+tre[rt<<1].rm;}int query(int q,int rt,int s,int e){ //到達葉子節點或是當前節點為空白或為滿的情況,直接返回。 if(s==e || tre[rt].sm==0 || tre[rt].sm==tre[rt].r-tre[rt].l+1) return tre[rt].sm; int m=(s+e)>>1; if(q<=m) { //若是在做孩子的右連續區間,那麼還要看右孩子的左連續區間 if(q>=tre[rt<<1].r-tre[rt<<1].rm+1) return query(q,lson)+query(m+1,rson); else return query(q,lson); } else { //同理~ if(q<=tre[rt<<1|1].lm+tre[rt<<1|1].l-1) return query(m,lson)+query(q,rson); else return query(q,rson); }}int main(){ int n,m; while(~scanf("%d%d",&n,&m)) { int top=-1; build(1,1,n); for(int i=0;i<m;i++) { int x; char str[5]; scanf("%s",str); if(str[0]=='D') { scanf("%d",&x); update(x,0,1,1,n); st[++top]=x; } else if(str[0]=='R') { int y=st[top--]; if(top>=-1) update(y,1,1,1,n); } else if(str[0]=='Q') { scanf("%d",&x); int k=query(x,1,1,n); printf("%d\n",k); } } } return 0;}