【BZOJ4864】【BJWC2017】神祕物質 - Splay
題意:
Description
21ZZ 年,冬。小誠退休以後, 不知為何重新燃起了對物理學的興趣。 他從研究所借了些實驗儀器,整天研究各種微觀粒子。這一天, 小誠剛從研究所得到了一塊奇異的隕石樣本, 便迫不及待地開始觀測。 在精密儀器的視野下,構成隕石的每個原子都無比清晰。 小誠發現, 這些原子排成若干列, 每一列的結構具有高度相似性。於是,他決定對單獨一列原子進行測量和測試。被選中的這列共有 N 個順序排列的原子。 最初, 第 i 個原子具有能量 Ei。 隨著時間推移和人為測試, 這列原子在觀測上會產生兩種變化:
merge x e 當前第 x 個原子和第 x+1 個原子合併,得到能量為 e 的新原子;
insert x e 在當前第 x 個原子和第 x+1 個原子之間插入一個能量為 e 的新原子。
對於一列原子,小誠關心的是相鄰一段中能量最大和能量最小的兩個原子的能量差值,
稱為區間極差。 因此, 除了觀測變化外,小誠還要經常統計這列原子的兩類資料:
max x y 當前第 x 到第 y 個原子之間的任意子區間中區間極差的最大值;
min x y 當前第 x 到第 y 個原子之間的任意子區間中區間極差的最小值。
其中, 子區間指的是長度至少是 2 的子區間。
小誠堅信這項研究可以獲得諾貝爾物理學獎。為了讓小誠早日了結心願,你能否幫助他實現上述的觀測和測量呢?
Input
Output
輸出若干行, 按順序依次表示每次 max 和 min 類事件的測量結果。
題解:
看到merge和insert操作肯定是splay維護啦……
考慮如何處理詢問,極差最大值肯定是區間最大值減最小值,這個不用說;
極差最小值呢?
結論是極差最小值一定是兩個相鄰的數之差;
考慮三個數,肯定選中間的數和與其差較小的另一個數極差最小,三個數都選不會優於這個選擇,類似歸納即可;
那麼splay維護子樹最大/最小值,前驅後繼和子樹內最小極差,pushup的時候搞搞即可。
程式碼:
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #define inf 1000000007
8 #define eps 1e-9
9 using namespace std;
10 typedef long long ll;
11 typedef double db;
12 struct node{
13 int son[2],fa,v,l,r,siz,mi,mx,mm;
14 }t[200001];
15 int n,m,x,y,rt,cnt,num[200001];
16 char op[10];
17 bool Son(int u){
18 return t[t[u].fa].son[1]==u;
19 }
20 void pushup(int u){
21 t[u].l=t[u].son[0]?t[t[u].son[0]].l:u;
22 t[u].r=t[u].son[1]?t[t[u].son[1]].r:u;
23 t[u].siz=t[t[u].son[0]].siz+t[t[u].son[1]].siz+1;
24 t[u].mx=max(t[u].v,max(t[t[u].son[0]].mx,t[t[u].son[1]].mx));
25 t[u].mi=min(t[u].v,min(t[t[u].son[0]].mi,t[t[u].son[1]].mi));
26 t[u].mm=min(min(t[t[u].son[0]].mm,t[t[u].son[1]].mm),min(t[u].son[0]?abs(t[u].v-t[t[t[u].son[0]].r].v):inf,t[u].son[1]?abs(t[u].v-t[t[t[u].son[1]].l].v):inf));
27 }
28 int build(int l,int r,int ff){
29 int mid=(l+r)/2;
30 t[mid].fa=ff;
31 if(l<mid)t[mid].son[0]=build(l,mid-1,mid);
32 if(mid<r)t[mid].son[1]=build(mid+1,r,mid);
33 pushup(mid);
34 return mid;
35 }
36 void rotate(int u){
37 int f=t[u].fa,ff=t[f].fa,ch=Son(u),cf=Son(f);
38 t[f].son[ch]=t[u].son[ch^1];
39 t[t[f].son[ch]].fa=f;
40 t[ff].son[cf]=u;
41 t[u].son[ch^1]=f;
42 t[u].fa=ff;
43 t[f].fa=u;
44 pushup(f);
45 pushup(u);
46 }
47 void splay(int u,int to){
48 for(;t[u].fa!=to;rotate(u)){
49 int f=t[u].fa;
50 if(t[f].fa!=to)rotate(Son(u)^Son(f)?u:f);
51 }
52 if(!to)rt=u;
53 }
54 int findx(int u,int k){
55 int nw=u;
56 for(;;){
57 if(t[t[nw].son[0]].siz+1==k)return nw;
58 if(k<=t[t[nw].son[0]].siz){
59 nw=t[nw].son[0];
60 }else{
61 k-=t[t[nw].son[0]].siz+1;
62 nw=t[nw].son[1];
63 }
64 }
65 }
66 int split(int x,int y){
67 int l=findx(rt,x-1),r=findx(rt,y+1);
68 //printf("%d %d\n",l,r);
69 splay(l,0);
70 splay(r,rt);
71 return t[t[rt].son[1]].son[0];
72 }
73 void merge(int x,int y){
74 int u=split(x+1,x+2);
75 t[u].v=y;
76 t[u].son[0]=t[u].son[1]=0;
77 pushup(u);
78 pushup(t[rt].son[1]);
79 pushup(rt);
80 }
81 void ins(int x,int y){
82 int u=split(x+2,x+1);
83 t[t[rt].son[1]].son[0]=++cnt;
84 t[cnt].fa=t[rt].son[1];
85 t[cnt].v=y;
86 pushup(cnt);
87 pushup(t[rt].son[1]);
88 pushup(rt);
89 }
90 int getmx(int x,int y){
91 int u=split(x+1,y+1);
92 return t[u].mx-t[u].mi;
93 }
94 int getmi(int x,int y){
95 int u=split(x+1,y+1);
96 return t[u].mm;
97 }
98 int main(){
99 scanf("%d%d",&n,&m);
100 cnt=n+2;
101 for(int i=1;i<=n;i++){
102 scanf("%d",&t[i+1].v);
103 }
104 t[0].mx=0;
105 t[0].mi=t[0].mm=inf;
106 cnt=n+2;
107 rt=build(1,n+2,0);
108 for(int i=1;i<=m;i++){
109 scanf("%s%d%d",op,&x,&y);
110 if(op[1]=='e'){
111 merge(x,y);
112 }else if(op[1]=='n'){
113 ins(x,y);
114 }else if(op[1]=='a'){
115 printf("%d\n",getmx(x,y));
116 }else{
117 printf("%d\n",getmi(x,y));
118 }
119 }
120 return 0;
121 }