官方題解:
• 假設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 注意 這裡的相同指的是點集與邊集均相同,...