1. 程式人生 > >hdu 1540(線段樹區間合併)

hdu 1540(線段樹區間合併)

題目連結:傳送門

參考文章:傳送門

題意:n個數字初始連在一條線上,有三種操作,

D x表示x號被摧毀;

R 表示恢復剩下的通路

Q表示查詢標號為x所在的串的最長長度。

思路:線段樹的區間合併。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 50500;
struct Node{
    int l,r;
    int ls,rs,ms;
}cur[maxn<<2]; 
int ss[maxn],m,n;
void build(int x,int l,int r) //初始化建樹 { cur[x].l=l;cur[x].r=r; cur[x].ls=cur[x].rs=cur[x].ms=r-l+1; if(l==r) return ; int mid=(l+r)>>1; build(x*2,l,mid); build(x*2+1,mid+1,r); } int MAX(int x,int y) { return x>y?x:y; } void update(int x,int pos,int fg) { if(cur[x].l==cur[x].r) {
if(fg==0) cur[x].ls=cur[x].rs=cur[x].ms=0; //刪除 else cur[x].ls=cur[x].rs=cur[x].ms=1; //更新 return ; } int mid=(cur[x].l+cur[x].r)>>1; if(pos<=mid) update(x*2,pos,fg); else update(x*2+1,pos,fg); //pushup操作,更新左子區間,右子區間的最長長度 cur[x].ls=cur[x*2].ls; cur[x].rs
=cur[x*2+1].rs; cur[x].ms=MAX(MAX(cur[x*2].ms,cur[x*2+1].ms),cur[x*2].rs+cur[x*2+1].ls); if(cur[x*2].ls==cur[x*2].r-cur[x*2].l+1) cur[x].ls+=cur[x*2+1].ls; //如果區間的左子樹的左區間已經滿了,就加上右子樹的左子區間 if(cur[x*2+1].rs==cur[x*2+1].r-cur[x*2+1].l+1) cur[x].rs+=cur[x*2].rs; // 如果右子樹的右子區間已經滿了,就加上左子樹的右子區間 } int query(int x,int pos) { if(cur[x].ms==0||cur[x].l==cur[x].r||cur[x].ms==cur[x].r-cur[x].l+1) return cur[x].ms; int mid=(cur[x].l+cur[x].r)>>1; if(pos<=mid) { if(pos>=cur[x*2].r-cur[x*2].rs+1) return query(x*2,pos)+query(x*2+1,mid+1);//如果在左子區間的右邊界,就遍歷兩個區間 return query(x*2,pos); } else { if(pos<=cur[x*2+1].l+cur[x*2+1].ls-1) return query(x*2+1,pos)+query(x*2,mid); //如果在右子區間的左邊界,就遍歷兩個區間 return query(x*2+1,pos); } } int main(void) { while(~scanf("%d%d",&n,&m)) { build(1,1,n); char op[2]; int x,top=0; while(m--) { scanf("%s",op); if(op[0]=='D') { scanf("%d",&x); ss[top++]=x; update(1,x,0); } else if(op[0]=='Q') { scanf("%d",&x); printf("%d\n",query(1,x)); } else if(op[0]=='R') { x=ss[--top]; update(1,x,1); } } } return 0; }
View Code