金題大戰Vol 0 B 序列 樹狀陣列

2022-01-10 17:19:39 字數 1589 閱讀 7404

給定兩個長度為 \(n\) 的序列\(a\), \(b\)。

你需要選擇乙個區間\([l,r]\),使得\(a_l+…+a_r>=0\)且\(b_l+…+b_r>=0\)。最大化你選擇的區間長度。

第一行乙個整數\(n\),第二行\(n\)個整數\(a_1-a_n\),第三行n個整數\(b_1-b_n\)。

一行乙個整數表示\(max(r-l+1)\)。保證至少有乙個區間滿足條件。

5

2 -4 1 2 -2

-2 3 1 -3 1

對於\(20\%\) 的資料,\(n<=5000\)。

對於\(60\%\) 的資料,\(n<=10^5\)。

對於\(100\%\) 的資料,\(1<=n<=10^6,|ai|, |bi|<=10^9\)。 資料有一定梯度。

乍看上去這一道題似乎不太好處理,要同時滿足下標、\(a\)、\(b\)三個條件

突破點就在於怎麼把限制條件一維一維地刪去

首先我們把題目中給出的陣列轉化成字首和的形式

即 \(suma[r]>=suma[l],sumb[r]>=sumb[l]\)

我們將 \(suma\) 從小到大排一下序

這樣我們每一次從左到右遍歷,就相當於消去了一維

我們只考慮 \(sumb\) 和座標的關係即可

這種關係我們可以用樹狀陣列去維護,即把 \(sumb\) 的值作為樹狀陣列的下標,把原先的編號作為樹狀陣列的權值

這樣在每次遇到乙個點時,我們在樹狀陣列中查詢 \(sumb\) 比它小的最小的下標

同時更新下標為 \(sumb\) 的節點的值為當前點的編號

\(sumb\) 比較大,並且有負數,因此考慮離散化

#includeusing namespace std;

const int maxn=1e6+5;

typedef long long ll;

inline int read()

while(ch>='0' && ch<='9')

return x*f;

}int a[maxn],b[maxn],n,cnt,tr[maxn];

ll suma[maxn],sumb[maxn];

struct asdjl[maxn];

bool cmp(asd aa,asd bb)

return ans;

}int main()

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

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

jl[i].wz=i;

} sort(jl+1,jl+1+n,cmp);

sort(sumb+1,sumb+1+n);

cnt=unique(sumb+1,sumb+1+n)-sumb-1;

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

ans=max(ans,jl[i].wz-bef);

ad(wz,jl[i].wz);

} printf("%d\n",ans);

return 0;

}

金題大戰Vol 0 D 二叉搜尋樹

有 n 個結點,第 i 個結點的權值為 i 你需要對它們進行一些操作並維護一些資訊,因此,你需要對它們建立一棵二叉搜尋樹。在整個操作過程中,第 i 個點需要被操作 x i 次,每次你需要從根結點一路走到第 i 個點,耗時為經過的結點數。最小化你的總耗時。第一行乙個整數 n 第二行 n 個整數 x1 ...

求因子和 百題大戰3

輸入正整數n 2 n 1000 計算並輸出n的所有正因子 包括1,不包括自身 之和。要求程式定義乙個facsum 函式和乙個main 函式,facsum 函式計算並返回n的所有正因子之和,其餘功能在main 函式中實現。int facsum int n 輸入輸入正整數n 2 n 1000 輸出輸出n...

P1197 JSOI2008 星球大戰 寫題筆記

include include include includeusing namespace std 倒過來求解 將全部有通道的點以邊的形式存起來,將所有要攻擊的點存起來 先將所有要拆除的點排除在外,把戰爭結束的最終結果的圖構建出來,把此時的連通塊數存起來 從後往前,把原本順序攻擊的點 反著構建回去...