線段樹複習

2022-05-07 21:51:11 字數 3620 閱讀 1630

p2572 [scoi2010]序列操作

這道題題解已經很多了

但是我還是想寫一篇

紀念 調三天**

思路 很簡單

struct node

tree[maxn << 2];

len:長度

sum:1的個數

lazy:把[a, b]區間內的所有數全變成0/1標記

rev:反轉標記

lsum[1/0]:記錄從左邊開始的最長連續1/0的個數

rsum[1/0]:記錄從右邊開始的最長連續1/0的個數

maxl[1/0]:記錄區間內最長連續1/0的個數

然後 就正常的線段樹操作了

主要是除錯

來說一些技巧

\(pushdown\)時 要麼左區間,要麼右區間

可以考慮 兩次\(pushdown\)

每次傳 現在區間標號 修改區間標號 修改區間長度

pushdown(k,k << 1,mid - l + 1);

pushdown(k,k << 1 | 1,r - mid);

r - mid !!不要+1!!

類似的

update(k,k << 1,k << 1 | 1,mid - l + 1,r - mid,0);

修改lsum[0],rsum[0],maxl[0]

update(k,k << 1,k << 1 | 1,mid - l + 1,r - mid,1);

修改lsum[1],rsum[1],maxl[1]

#include #include #include #include #include using namespace std;

#define reg register int

#define isdigit(x) ('0' <= x&&x <= '9')

templateinline t read(t type)

while(isdigit(a))

return x * f;

}const int maxn = 100010;

struct segment_tree

tree[maxn << 2];

void update(int k,int k1,int k2,int lenl,int lenr,int x)

void build(int k,int l,int r)

int mid = l + r >> 1;

tree[k].lazy = -1,tree[k].rev = 0;

build(k << 1,l,mid);

build(k << 1 | 1,mid + 1,r);

update(k,k << 1,k << 1 | 1,mid - l + 1,r - mid,0);

update(k,k << 1,k << 1 | 1,mid - l + 1,r - mid,1);

} void pushdown(int k,int k1,int len)

if(tree[k].rev)

}void change(int k,int l,int r,int l,int r,int x)

int mid = l + r >> 1;

pushdown(k,k << 1,mid - l + 1);

pushdown(k,k << 1 | 1,r - mid);

tree[k].lazy = -1,tree[k].rev = 0;

if(l <= mid) change(k << 1,l,mid,l,r,x);

if(mid < r) change(k << 1 | 1,mid + 1,r,l,r,x);

update(k,k << 1,k << 1 | 1,mid - l + 1,r - mid,0);

update(k,k << 1,k << 1 | 1,mid - l + 1,r - mid,1);

} void inverse(int k,int l,int r,int l,int r)

int mid = l + r >> 1;

pushdown(k,k << 1,mid - l + 1);

pushdown(k,k << 1 | 1,r - mid);

tree[k].lazy = -1,tree[k].rev = 0;

if(l <= mid) inverse(k << 1,l,mid,l,r);

if(mid < r) inverse(k << 1 | 1,mid + 1,r,l,r);

update(k,k << 1,k << 1 | 1,mid - l + 1,r - mid,0);

update(k,k << 1,k << 1 | 1,mid - l + 1,r - mid,1);

} int query(int k,int l,int r,int l,int r)

node sum(int k,int l,int r,int l,int r)

int mid = l + r >> 1;

pushdown(k,k << 1,mid - l + 1);

pushdown(k,k << 1 | 1,r - mid);

tree[k].lazy = -1,tree[k].rev = 0;

node k1[2];

memset(k1,0,sizeof(k1));

if(l <= mid) k1[0] = sum(k << 1,l,mid,l,r);

if(mid < r) k1[1] = sum(k << 1 | 1,mid + 1,r,l,r);

update(k,k << 1,k << 1 | 1,mid - l + 1,r - mid,0);

update(k,k << 1,k << 1 | 1,mid - l + 1,r - mid,1);

node k3;

k3.maxl[1] = max(k1[0].maxl[1],max(k1[1].maxl[1],k1[0].rsum[1] + k1[1].lsum[1]));

k3.lsum[1] = k1[0].lsum[1];

if(k1[0].lsum[1] == k1[0].len) k3.lsum[1] += k1[1].lsum[1];

k3.rsum[1] = k1[1].rsum[1];

if(k1[1].rsum[1] == k1[1].len) k3.rsum[1] += k1[0].rsum[1];

k3.len = k1[0].len + k1[1].len;

//不要忘了算len 這行沒寫 只會wa兩個點

return k3;

}}t;

int main()

} return 0;

}

這種毒瘤資料結構題

先靜態查錯

再對拍然後求助

或者直接求助

幫助工具

如果還沒調出來 可以嘗試以下方式

小蒟蒻皮皮魚 提供的對拍程式

#includeusing namespace std;

int main()

}

ljc00118 提供的

資料生成程式

RMQ 線段樹複習

首先是rmq include include includeusing namespace std const int maxn 50000 100 int dmax maxn 20 int dmin maxn 20 void initmax int n,int d 初始化最大值查詢 遞迴建立線段樹...

複習 線段樹基礎

大部分題目是純模板,只寫一下 山海經 題意 查詢區間最大欄位和 不帶修 考慮區間最大子段和由 貢獻得到,可能是lson的ans,rson的ans,也可以是lson與rson拼接而成 只需要抽象出加法 push up 操作,就很好理解了 網上題解太麻煩,需要各種分類討論,容易寫掛 所以直接抽象出加法即...

線段樹合併複習筆記

線段樹合併和主席樹不同的是。主席樹的節點還要依賴之前的樹結構。而線段樹合併是若干個分離的線段樹合併起來,在建立節點的時候有些不同。按照dfs的順序處理。顯然乙個子樹內的交換只會影響該子樹,所以可以貪心得對於每個子樹決定是否交換。算到葉子節點的時候新建一顆log loglo g個節點的權值線段樹。合併...