bzoj1500 NOI2005 維修數列

2021-08-01 21:51:15 字數 3061 閱讀 9914

time limit: 10 sec  

memory limit: 64 mb

submit: 14170  

solved: 4575 [

submit][

status][

discuss]

輸入的第1 行包含兩個數n 和m(m ≤20 000),n 表示初始時數列中數的個數,m表示要進行的運算元目。

第2行包含n個數字,描述初始時的數列。

以下m行,每行一條命令,格式參見問題描述中的**。

任何時刻數列中最多含有500 000個數,數列中任何乙個數字均在[-1 000, 1 000]內。

插入的數字總數不超過4 000 000個,輸入檔案大小不超過20mbytes。

對於輸入資料中的get-sum和max-sum操作,向輸出檔案依次列印結果,每個答案(數字)佔一行。

9 82 -6 3 5 1 -5 -3 6 3

get-sum 5 4

max-sum

insert 8 3 -5 7 2

delete 12 1

make-same 3 3 2

reverse 3 6

get-sum 5 4

max-sum

-110110

submit][

status][

discuss]

對於乙個剛學splay的蒟蒻來說有點困難啊。。。

於是改了好幾天。

講一些比較重要的東西:

每個操作需要將splay轉成乙個結構:把右端點右邊後繼ro旋轉到根,再把左端點前驅lo旋轉到ro的左兒子,

這樣,目標區間即為lo的右兒子

為了方便判斷邊界的問題,需要加入兩個虛擬節點,即左邊界與右邊界

然後後面的操作就比較好執行了

講一下max-sum:

需要維護lsum,rsum,maxs,分別表示該區間內從左開始向右數的最大連續和,從右往左數的最大連續和以及該區間內的最大子段和

lsum的維護要分成三種情況,一種取值為lsum[lc],一種取值為sum[lc]+v[o],另一種取值為sum[lc]+v[當前節點]+lsum[rc],三種情況取乙個max值,

rsum與lsum同理。

而maxs大體上分兩種討論:

一種為最大子段和跨越了當前節點o,一種沒有;

後者相對容易,只需在maxs[lc],maxs[rc]取乙個max值就好

而前者就為lsum[rc]+v[當前節點]+rsum[lc]

兩種情況取乙個max

幾個蒟蒻的wa點:

1、點0的最大子段和要初始化為-inf

2、注意到當覆蓋時,若覆蓋的權值為負數,則lsum與rum需設定為0(而不是setv[o]),而maxs需為setv[o]

人生中第二個splay,收穫頗豐

**:

#include#include#include#include#include#includeusing namespace std;

const int maxn = 500100;

const int inf = 2e9;

int q[500000];

char s[40];

bool flag[maxn],setf[maxn];

int a[maxn];

int n,m,cur,rt,st,ed,tot = 0,fa[maxn],ch[maxn][2],v[maxn],top;

int setv[maxn],lsum[maxn],rsum[maxn],maxs[maxn],sum[maxn],siz[maxn]; //附加資訊

inline void swap(int& x,int& y)

inline void maintain(int o)

inline void cover(int o,int x)

inline void reverse(int o)

inline void pushdown(int o)

if (setf[o])

}inline void output(int o)

inline int check(int o)

inline void rotate(int x)

}inline int kth(int o,int k)

inline void pushdown_root(int x)

inline void splay(int x)

inline void rever(int l,int r)

inline int qsum(int l,int r)

inline int maxsum()

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

v[x] = a[mid]; fa[x] = f;

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

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

maintain(x);

return x;

}inline void insert(int pos,int toti)

inline void del(int o)

inline void remove(int l,int r)

inline void update(int l,int r,int c)

inline int getint()

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

ret = ret * 10 + c - '0',c = getchar();

return ret * f;

}int main()

if (!strcmp(s,"delete"))

if (!strcmp(s,"make-same"))

if (!strcmp(s,"reverse"))

if (!strcmp(s,"get-sum"))

if (!strcmp(s,"max-sum"))

printf("%d\n",maxsum());

}return 0;

}

BZOJ1500 NOI2005 維修數列

description input 輸入檔案的第1行包含兩個數n和m,n表示初始時數列中數的個數,m表示要進行的運算元目。第2行包含n個數字,描述初始時的數列。以下m行,每行一條命令,格式參見問題描述中的 output 對於輸入資料中的get sum和max sum操作,向輸出檔案依次列印結果,每個...

bzoj1500 NOI2005 維修數列

splay鼻祖級的題目?霧。insert 把第pos個數 有哨兵節點 轉到root,把第pos 1個數轉到root的右兒子,然後對c建樹然後把這棵樹插到root右兒子的左兒子處 delete 把第pos個數轉到root,把第pos tot 1個數轉到root右兒子,刪掉root右兒子的左兒子 變成0...

BZOJ 1500 NOI2005 維修數列

輸入的第1 行包含兩個數n 和m m 20 000 n 表示初始時數列中數的個數,m表示要進行的運算元目。第2行包含n個數字,描述初始時的數列。以下m行,每行一條命令,格式參見問題描述中的 任何時刻數列中最多含有500 000個數,數列中任何乙個數字均在 1 000,1 000 內。插入的數字總數不...