【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

第一行, 两个整数 N, M, 分别表示最初的原子数目和事件总数。
第二行, N 个整数 E1, E2, …, EN, 由空格隔开。依次表示每个原子的能量。
接下来 M 行, 每行为一个字符串和两个整数, 描述一次事件,格式见题目描述。
N<=100,000,M<=100,0001 ≤ e, Ei ≤ 109。
设 N’ 为当前时刻原子数目。对于 merge 类事件, 1 ≤ x ≤ N’-1;
对于 insert 类事件, 1 ≤ x ≤ N’;
对于 max 和 min 类事件, 1 ≤ x < y ≤ N’。
任何时刻,保证 N’ ≥ 2。

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 }
posted @ 2019-01-10 15:37  DCDCBigBig  阅读(292)  评论(0编辑  收藏  举报