ZJOI2007報表統計 BZOJ1058

2022-07-29 17:00:22 字數 3692 閱讀 1674

傳送門:

time limit: 15 sec  memory limit: 162 mb

小q的媽媽是乙個出納,經常需要做一些統計報表的工作。今天是媽媽的生日,小q希望可以幫媽媽分擔一些工作,作為她的生日禮物之一。經過仔細觀察,小q發現

統計一張報表實際上是維護乙個非負整數數列,並且進行一些查詢操作。在最開始的時候,有乙個長度為n的整數序列,並且有以下三種操作: insert i

k 在原數列的第i個元素後面新增乙個新元素k; 如果原數列的第i個元素已經新增了若干元素,則新增在這些元素的最後(見下面的例子)

min_gap 查詢相鄰兩個元素的之間差值(絕對值)的最小值 min_sort_gap 查詢所有元素中最接近的兩個元素的差值(絕對值)

例如一開始的序列為 5 3 1 執行操作insert 2 9將得到: 5 3 9 1 此時min_gap為2,min_sort_gap為2。

再執行操作insert 2 6將得到: 5 3 9 6 1

注意這個時候原序列的第2個元素後面已經新增了乙個9,此時新增的6應加在9的後面。這個時候min_gap為2,min_sort_gap為1。於是小

q寫了乙個程式,使得程式可以自動完成這些操作,但是他發現對於一些大的報表他的程式執行得很慢,你能幫助他改進程式麼?

第一行包含兩個整數n,m,分別表示原數列的長度以及操作的次數。第二行為n個整數,為初始序列。接下來的m行每行乙個操作,即「insert i k」,「min_gap」,「min_sort_gap」中的一種(無多餘空格或者空行)。

對於每乙個「min_gap」和「min_sort_gap」命令,輸出一行答案即可。

3 55 3 1

insert 2 9

min_sort_gap

insert 2 6

min_gap

min_sort_gap22

1對於30%的資料,n ≤ 1000 , m ≤ 5000 對於100%的資料,n , m ≤500000 對於所有的資料,序列內的整數不超過5*108。

臥槽。。這題真tm噁心。。我從上午改到現在。。原因是tle。。(媽蛋我要不是抱著試一試的心情交了這次我都不知道我特麼ac了。。)在下面測,最慢的要2s多。。就不敢交

不過第乙個版本的動態插入式的還是tle。。優化的版本是直接build樹。。沒什麼好說的。。ttttttttttttt________________ttttttttttttt...

codes:

1 #include

2 #include3 #include4 #include5 #include6 #include7 #include8 #include9

using

namespace

std;

10const

int n = 500010;11

#define sets(t,a,b,c)

12#define rep(i,n) for(int i=1;i<=n;i++)

13#define for(i,l,r) for(int i=l;i<=r;i++)

1415

struct

tnodet1[n<<1],t2[n<<1

];18

19int kth,val,a[n],last[n],msg=2147483647

,n,m;

20int

cnt,root1,root2,tot1,tot2,y,z;

2122

intread()

29while(ch>='

0'&&ch<='9'

)33return (q==1)?(-num):num;34}

3536

void rot(tnode t,int

x)44

45void splay(tnode t,int i,int goal,int &root)

50if(!goal) root =i;51}

5253

void insert_1(int v,int

i)58 msg = min(msg,abs(v-t1[i].v));

59if(t1[i].v==v) t1[i].num++;

60else

65else insert_1(v,t1[i].s[v>t1[i].v]);66}

67}6869

void insert_2(int v,int

i)74

if(t2[i].v==v) t2[i].num++;

75else

80else insert_2(v,t2[i].s[v>t2[i].v]);81}

82}8384

int prev(int

i)89

90void delete(int

i)95 splay(t2,i,0

,root2);

96if(t2[i].s[0

])else

103else root2 = 0

;104

}105 t2[i].num = t2[i].p = t2[i].s[0] = t2[i].s[1] = t2[i].v = 0

;106

}107

108int min(int

root2)

114115

int find(int v,int

i)119

120void build1(int l,int r,int &i,int

p)127

128void build2(int l,int r,int &i,int

p)135

136int

main()

147 sort(last+1,last+n);

148 build2(1,n-1,root2,0

);149 rep(i,n) last[i] =a[i];

150 sort(a+1,a+n+1);for(i,1,n-1) msg=min(msg,abs(a[i]-a[i+1

]));

151 build1(1,n,root1,0

);152 rep(i,n) a[i] =last[i];

153char op[20];int

troot;

154rep(i,m)

162 insert_2(abs(val-last[kth]),root2);

163if(kth1

]),root2);

164insert_1(val,root1);

165 last[kth] =val;

166continue

;167

}168

if(op[4]=='

s') printf("

%d\n

",msg);

169if(op[4]=='

g') printf("

%d\n

",min(root2));

170}

171//

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

172return0;

173 }

好長。。t___t。。好像還沒說做法,我sb地建了兩棵平衡樹。。一棵維護min_gap 一棵維護min_sort_gap。。

實際上,可以用堆維護min_gap。。或者是set。。

ZJOI2007 報表統計

不想描述了,心累。兩個操作分別用splay和線段樹來維護 全域性的差值最小直接用splay在插入的時候維護前驅後繼即可 相鄰最小差值我們可以這樣搞 首先 用線段樹維護相鄰的最小值 可以注意到插入元素的操作,如果是在乙個元素之後反覆插入,這些元素之間更新出來的最小值是不會發生改變的。只有元素與元素之間...

ZJOI2007 報表統計

在原數列第 i 個後面新增乙個新元素 k 如果原數列的第 i 個元素已經新增了若干元素,則新增在這些元素的最後。查詢相鄰兩個元素的差值的絕對值的最小值。查詢所有元素中一對元素的差值的絕對值的最小值。第乙個操作很好維護,若要在第 i 個元素後面插值,那麼實際需要插入的位置是 i s i 1 其中 s ...

ZJOI2007 報表統計

題解 一道不錯的模板題 對於第乙個詢問,只需維護乙個支援刪除的堆 方法1.再維護乙個堆,將刪除的數加入這個堆,每次取元素時判斷一下是否和另乙個堆相等 方法2.利用左偏樹可以刪除任意節點 太久不寫都忘了 當然也可以維護一顆平衡樹 對於第二個詢問,只需弄一顆平衡樹求它的前驅後繼就可以了 include ...