牛客網 sequence 線段樹 單調棧

2021-09-25 16:32:14 字數 1584 閱讀 2448

官方題解:

• 假設a中的元素互不相同,我們考慮a中的某個元素作為min的時刻。

• 對於每個a[i],我們找到左邊第乙個比它大的元素a[l],右邊第乙個比它大的a[r]

• 那麼左端點在[l+1,i],右端點在[i,r-1]的區間min就為它。

• 求l和r可以使用單調棧。

• 考慮如何求某個a[i]作為min的答案。

• 如果a[i]>0我們就是要最大化sum(b[l..r])。a[i]<0就是要最小化。

• 記b的字首和為s,那麼sum(b[l..r])=s[r]-s[l-1]。

• 所以我們只要查詢i..r-1最大的s和l..i-1最小的s,相減即可。

• 查詢區間最小值可以使用st表或線段樹等資料結構。

• 也可以直接建立笛卡爾樹,然後維護子樹中s的最大最小值,從而做到o(n)的複雜度。 

所以我們只需要維護b陣列的字首和的最大和最小,每次在右區間裡找乙個位置sr, 在左區間找乙個位置sl,sr-sl就是區間b陣列[ l + 1, r]的字首和。

#include using namespace std;

typedef long long ll;

#define lson l, mid, rt << 1

#define rson mid + 1, r, rt << 1|1

const int maxn = 3e6 + 10;

const ll linf = 0x3f3f3f3f3f3f3f3f;

ll sum[maxn << 2], max[maxn << 2], min[maxn << 2];

int a[maxn], pre[maxn], last[maxn];

stacks;

void push_up(int rt)

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

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

build(lson);

build(rson);

push_up(rt);

}ll query_max(int l, int r, int l, int r, int rt)

ll query_min(int l, int r, int l, int r, int rt)

int main()

build(0, n, 1);

a[0] = a[n + 1] = -1e9;

s.push(0);

for(int i = 1; i <= n; ++i) //找到左邊第乙個小的

while(!s.empty())

s.pop();

s.push(n + 1);

for(int i = n; i >= 1; --i) //找到右邊第乙個小的

ll ans = -linf;

for(int i = 1; i <= n; ++i)

printf("%lld\n", ans);

return 0;

}

sequence 牛客 ( 線段樹)

題面 your are given two sequences a1 n,b1 n a b a1 n b1 n you need to answer max 1 l r n displaystyle max times sum b 1 l r nmax 1e 6 b i 1e 6 1e6 1 e6 ...

牛客網 剩下的樹 線段樹入門

mn o mn o mn 複雜度都可以過,可以見得資料之水當然這道題的資料量本身也是符合這個複雜度的,ps fill和memset別用得太多,有時候會被卡死 include include include include include include include include using n...

牛客網A 生成樹

你有一張n個點的完全圖 即任意兩點之間都有無向邊 現在給出這張圖的兩棵生成樹 定義一次操作為 在任意一棵生成樹中刪除一條邊後再加入一條邊 必須在同一棵樹中操作 同時需要保證操作完後仍然是一棵樹 問使得兩棵樹相同的最少操作次數,若不存在合法的操作方案,輸出 1 注意 這裡的相同指的是點集與邊集均相同,...