題意:1-n個地道,m個次操作,d代表摧毀第i個地道,q代表查詢包含第i個地道的最大連續地道數目,並輸出。r代表修復最近摧毀的那個地道;
思路:這題利用了線段樹的相鄰結點區間是連續的特性,而且是維護連續的1,所以用llen、rlen、len陣列分別表代表當前結點的1的最長連續字首長、最長連續字尾長,最長連續區間長,對於某個結點,它的最長連續字首等於它的左子結點的最長連續字首,如果它的左子結點的最長連續字首包含了整個左子區間,那麼這個結點的最長連續字首還要加上右子結點的最長連續字首;同理,對於某個結點的最長連續字尾是一樣的,這裡不贅述。而對於某個結點的最長連續區間應該是它的最長連續字首、最長連續字尾、它的左子結點的最長連續字尾+右子結點的最長連續字首 三者中的最大值,所以pushup函式就可以寫出來了。建樹和更新的時候直接在l==r的時候賦值即可。對於查詢,**注釋已經給出,畫一下圖很好理解的。
#includeusing namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn=50005;
const int mod=1e9+7;
const double eps=1e-8;
const double pi = acos(-1.0);
#define lowbit(x) (x&(-x))
int len[maxn<<2],llen[maxn<<2],rlen[maxn<<2];
void pushup(int rt,int length)
void build(int l,int r,int rt)
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushup(rt,r-l+1);
}void update(int loc,int c,int l,int r,int rt)
int m=(l+r)>>1;
if(loc<=m) update(loc,c,l,m,rt<<1);
if(loc>m) update(loc,c,m+1,r,rt<<1|1);
pushup(rt,r-l+1);
}int query(int loc,int l,int r,int rt)
else
}int main()
else if(c=='r')
else}}
return 0;
}
線段樹 區間合併 HDU 1540
題意 題意 d 破壞村莊,r 修復最後乙個破損的村莊,q 查詢x在內的連續區間值有多少 思路 建立線段樹,維護左右區間值。注意維護變數為 從左編開始最大連續值,從右邊開始最大值,最大連續值 為了維護最後乙個被破壞的。需要時刻記錄,並且不能只單純記錄乙個,而是需要記錄順序。滿足先入後出的棧操作,傳參即...
線段樹(區間合併)HDU 1540
題意 輸入n,m,給定n個相互連通的村莊,有m個操作,d x,表示破壞x村莊使其與相鄰的兩個村莊不相通,r 表示修復上乙個被破壞的村莊,與相鄰的兩個村莊聯通。q x表示與x相連的村莊有多少個。思路 一開始只知道是線段樹,想著肯定得用結構體記錄每個點的資訊,怎麼記錄就不知道了。然後學了線段樹區間合併。...
HDU 1540 線段樹左右區間合併
題目大概的意思就是求當前這個村莊,左右連續的村莊共有幾個,包括自己。思路 比較容易想到的就是把用線段樹劃分的每乙個區間的左右連續區間長度記錄下來,然後嘗試著吧x這個村莊的左右連續並且沒被摧毀的村莊個數連起來,就能得出答案了。具體看 的注釋 include include include includ...