P2042 NOI2005 維護數列

2022-08-13 00:54:16 字數 2963 閱讀 8685

這道題看到什麼維護序列的,肯定就是用資料結構的。

這個東西叫你做下面的事情:

首先確定用什麼資料結構。

看到翻轉,二話不說就用splay。

第乙個操作:在第posi位後加入tot個數字。我們就把這一段數字建出乙個子splay。用類似線段樹的建樹方式解決掉,比乙個乙個加入的建樹方式快,常數小。然後split出來中間的位置,暴力連線,pushup即可。

第二個操作:在第posi位後連續刪除tot個數字。我們spilt出來這段數字,然後暴力斷開與主splay的鏈結。主splaypushup一下,子splay就直接刪除掉即可。

第三個操作:推平一段區間。我們使用lazy標記記錄一下即可。我們先表面改好,然後再給子節點加lazy標記。聽起來不難。

第四個操作:區間翻轉。我們同樣使用懶標記的思想。具體操作看「文藝平衡樹」那道模板題。

第五個操作:求區間和。維護一下就是了。。。

第六個操作:求最大子串行。

\(o(n)\)的演算法能求乙個固定數的最大子串行,但是一次修改就得跟乙個\(o(n)\)是很慢的。

其實最大子串行有乙個分治解法,是\(o(nlogn)\)的。這種方法可以用到線段樹裡面,使得乙個修改是\(o(logn)\)的。

具體就是乙個節點跟三個變數:mxlxrx

如何更新?放在pushup裡面更新。更新方法像在dp一樣:

\(lx[l,r]=max(lx[l,mid],sum[l,mid]+lx[mid+1,r])\)

\(rx[l,r]=max(rx[mid+1,r],sum[mid+1,r]+rx[l,mid])rx[l,r]=max(rx[mid+1,r],sum[mid+1,r]+rx[l,mid])\)

\(mx[l,r]=max(mx[l,mid],mx[mid+1,r],lx[mid+1,r]+rx[l,mid+1])mx[l,r]=max(mx[l,mid],mx[mid+1,r],lx[mid+1,r]+rx[l,mid+1])\)

放在平衡樹也簡單,不就是多出了乙個單獨的節點\(mid\)嗎?算進去就是了。

接下來麻煩的就來了!如何搞定這些懶標記的複雜關係?

顯然,乙個有推平標記的翻轉沒意義。所以可以直接忽略掉。所以先處理推平,後處理翻轉。

翻轉不只要交換左右兒子!還需要交換lxrx

翻轉的寫法我之前是直接改標記後就走人,所以他上面的根本就沒改到。如果單純只叫你維護翻轉的話那樣寫是沒問題的。

**:

#include#include#includeconst int maxn = 500005;

const int inf = 0x3f3f3f3f;

int a[maxn], id[maxn];

int fa[maxn], size[maxn], ch[maxn][2];

int val[maxn], sum[maxn];

int lx[maxn], mx[maxn], rx[maxn];

bool lazy[maxn], rev[maxn];

int root, tot;

int n, m;

std::stacksta;

#define lson ch[x][0]

#define rson ch[x][1]

int read()

while(ch >= '0' && ch <= '9') ans = (ans << 3) + (ans << 1) + ch - '0', ch = getchar();

return s * ans;

}int newnode()

return ++tot;

}void clear_it(int x)

int dir(int x)

void connect(int son, int f, int k)

void pushup(int x)

void rotate(int x)

void splay(int x, int goal)

if(goal == 0) root = x;

}void pushdown(int x)

if(rson)

}if(rev[x])

}int build(int f, int l, int r)

int mid = (l + r) >> 1;

val[id[mid]] = a[mid];

fa[id[mid]] = id[f];

ch[id[mid]][0] = build(mid, l, mid - 1);

ch[id[mid]][1] = build(mid, mid + 1, r);

pushup(id[mid]);

return id[mid];

}int kth(int k)

else if(size[lson] >= k) x = lson;

else return x;

}}int split(int l, int r)

void recycle(int x)

// functions

void insert()

void delete()

void reverse()

void getsum()

void makesame()

void maxsum()

// debug

void print(int x)

int main()

return 0;

}

P2042 NOI2005 維護數列

超級噁心的pushdown 昏天黑地的調 讓我想起了我那前幾個月的線段樹2 這噁心的一道題終於過了 太多錯誤,簡直說不過來 pushup pushdown 主要就是這倆不太清晰,亂pushdown 其他的寫的還沒啥毛病 能看出來 include include include include inc...

P2042 NOI2005 維護數列 平衡樹

最大序列和小白逛公園做過 區間修改的優先順序高於區間翻轉的優先順序 之前有題01串翻轉 序列維護平衡樹 平衡樹維護的是下標 因此中序遍歷就是原序列 每個結點維護的都是結點 不像線段樹可以維護區間 所以build 的操作有一些不一樣 這題還卡空間 所以要弄乙個簡單的 操作 注意up的順序 必須從下到上...

洛谷 P2042 NOI2005 維護數列

一直在想要做這道題,但是被那個碩大的splay標籤壓垮了 好了,切入正題 這道題應該是我第二次用splay來維護區間問題 我還是太菜了qaq 其實思路也很簡單,就是以每乙個位置的下標來進行維護,然後其實就是跟權值樹是一模一樣的了 然後再具體說一下 為了保證效率,像線段樹和文藝平衡樹一樣,我們可以維護...