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 內。插入的數字總數不...