原题链接:P1110 [ZJOI2007]报表统计
题意
题意是很简单的。。
就是一开始有$n$个元素,每个元素相当于一个队列,总的序列是所有队列按顺序拼接起来的序列,有下面三种操作。
操作一:在原序列第$k$个队列插入一个$x$
操作二:查询总序列里面相邻元素的差值的绝对值的最小值。
操作三:查询总序列里面所有元素差值的绝对值的最小值。
分析
第一个操作应该是建立在二,三操作的基础上进行的。。
我们先对二,三操作进行讨论。
第三个操作比较简单,我们只要建立一个平衡树,每次插入元素之后,查询这个元素和排名相邻的元素的差值,然后统计出最小值就可以了。
重点是第二个操作。
发现如果我们插入一个元素,这个元素会打破一对元素的相邻关系,并且建立两队相邻关系,每次的答案就是所有的相邻关系中差值最小的一对。
差值最小的一对很容易用堆来维护,我们的问题就变成了维护一个可以删除的堆。
这个堆也很容易实现。。
我们开两个堆,第一个堆储存已经插入的数,第二个堆储存已经删除的数,每次弹出时我们只需要判断两堆的堆顶是不是一样,如果一样就同时弹掉,直到堆顶不一样。
那么第一个操作就是这两个操作的结合了吧。。不讲了。。
注意平衡树判断前驱,后继的时候要注意判断当前元素是否有多个,如果有多个的话说明最小值是零。
同时有一个卡常小技巧。。
最小值是一直向着$0$贴近的,不会变成负数也不会变大,所以当我们发现最小值变成$0$的时候,我们就不需要再进行平衡树操作了(卡了这个之后我代码快了700ms)。
当然最开始的时候我们要对所有的数据进行初始化,确定每个数据在最终的数组中的位置。(不然用vector好像也是可以的,没试过,你们可以去试试)
下面就直接贴代码(常熟巨大不开氧气2336ms,开了氧气也是830ms)
代码
1 #include <bits/stdc++.h> 2 #define fa(x) tree[x].fa 3 #define son(x,k) tree[x].ch[k] 4 #define cnt(x) tree[x].cnt 5 #define val(x) tree[x].val 6 #define siz(x) tree[x].siz 7 using namespace std; 8 const int N=5e6+1009; 9 const int inf=(1<<31)-1; 10 struct Hp{ 11 priority_queue<int>q1,q2; 12 Hp(){ 13 while(!q1.empty())q1.pop(); 14 while(!q2.empty())q2.pop(); 15 } 16 void Insert(int x){ 17 q1.push(-x); 18 } 19 void Delete(int x){ 20 q2.push(-x); 21 } 22 int Top(){ 23 while(!q2.empty()&&!q1.empty()){ 24 if(q1.top()!=q2.top())return -q1.top(); 25 q1.pop();q2.pop(); 26 } 27 } 28 }Heap; 29 int read(){ 30 char c;int num,f=1; 31 while(c=getchar(),!isdigit(c))if(c=='-')f=-1;num=c-'0'; 32 while(c=getchar(), isdigit(c))num=num*10+c-'0'; 33 return f*num; 34 } 35 int abs(int x){return x<0?-x:x;} 36 int rt,tot; 37 int n,m,pos[N],minn=(1<<31)-1; 38 int ord[N][10],a[N],b[N]; 39 40 struct Node{ 41 int fa,ch[2],siz,cnt,val; 42 }tree[N]; 43 bool chk(int x){return son(fa(x),1)==x;} 44 void update(int x){siz(x)=siz(son(x,0))+siz(son(x,1))+cnt(x);} 45 int New(int x,int pre){ 46 tot++; 47 if(pre)son(pre,x>val(pre))=tot; 48 son(tot,0)=son(tot,1)=0; 49 cnt(tot)=siz(tot)=1; 50 val(tot)=x;fa(tot)=pre; 51 return tot; 52 } 53 void rotate(int x){ 54 int y=fa(x),z=fa(y),k=chk(x); 55 son(z,chk(y))=x;fa(x)=z; 56 son(y,k)=son(x,k^1);fa(son(x,k^1))=y; 57 son(x,k^1)=y;fa(y)=x; 58 update(y);update(x); 59 } 60 void splay(int x,int goal=0){ 61 while(fa(x)!=goal){ 62 int y=fa(x),z=fa(y); 63 if(z!=goal){ 64 if(chk(y)==chk(x))rotate(y); 65 else rotate(x); 66 } 67 rotate(x); 68 } 69 if(!goal)rt=x; 70 } 71 void Insert(int x){ 72 int cur=rt,p=0; 73 while(cur&&val(cur)!=x) 74 p=cur,cur=son(cur,x>val(cur)); 75 if(cur)cnt(cur)++; 76 else cur=New(x,p); 77 splay(cur); 78 } 79 void Find(int x){ 80 if(!rt)return ; 81 int cur=rt; 82 while(son(cur,x>val(cur))&&val(cur)!=x) 83 cur=son(cur,x>val(cur)); 84 splay(cur); 85 } 86 int Pre(int x){ 87 Find(x); 88 if(val(rt)<x||(val(rt)==x&&cnt(rt)>1))return rt; 89 int cur=son(rt,0); 90 while(son(cur,1))cur=son(cur,1); 91 return cur; 92 } 93 int Succ(int x){ 94 Find(x); 95 if(val(rt)>x||(val(rt)==x&&cnt(rt)>1))return rt; 96 int cur=son(rt,1); 97 while(son(cur,0))cur=son(cur,0); 98 return cur; 99 } 100 int main() 101 { 102 n=read();m=read(); 103 Insert(inf);Insert(-inf); 104 for(int i=1;i<=n;i++){ 105 int x=read(); 106 pos[i]=x; 107 b[i]++; 108 } 109 for(int i=1;i<=m;i++){ 110 char c[19]; 111 scanf("%s",c); 112 int len=strlen(c); 113 if(len==6){ 114 ord[i][0]=1; 115 ord[i][1]=read(); 116 ord[i][2]=read(); 117 b[ord[i][1]]++; 118 ord[i][3]=b[ord[i][1]]; 119 }else if(len==7)ord[i][0]=2; 120 else ord[i][0]=3; 121 } 122 for(int i=1;i<=n;i++){ 123 if(i!=1)Heap.Insert(abs(pos[i]-pos[i-1])); 124 if(minn!=0){ 125 Insert(pos[i]); 126 int xx=val(Succ(pos[i])),yy=val(Pre(pos[i])); 127 if(xx!=inf&&xx!=-inf)minn=min(minn,xx-pos[i]); 128 if(yy!=inf&&yy!=-inf)minn=min(minn,pos[i]-yy); 129 } 130 a[b[i-1]+1]=pos[i]; 131 //cout<<b[i-1]+1<<endl; 132 b[i]+=b[i-1]; 133 } 134 //cout<<Heap.Top()<<endl; 135 for(int i=1;i<=m;i++){ 136 if(ord[i][0]==1){ 137 if(minn!=0) Insert(ord[i][2]); 138 a[b[ord[i][1]-1]+ord[i][3]]=ord[i][2]; 139 140 Heap.Insert(abs(a[b[ord[i][1]-1]+ord[i][3]]-a[b[ord[i][1]-1]+ord[i][3]-1])); 141 Heap.Insert(abs(a[b[ord[i][1]-1]+ord[i][3]]-a[b[ord[i][1]]+1])); 142 Heap.Delete(abs(a[b[ord[i][1]]+1]-a[b[ord[i][1]-1]+ord[i][3]-1])); 143 if(minn!=0){ 144 int xx=val(Succ(ord[i][2])),yy=val(Pre(ord[i][2])); 145 if(xx!=inf&&xx!=-inf)minn=min(minn,xx-ord[i][2]); 146 if(yy!=inf&&yy!=-inf)minn=min(minn,ord[i][2]-yy); 147 } 148 }else if(ord[i][0]==2) 149 printf("%d ",Heap.Top()); 150 else printf("%d ",minn); 151 } 152 return 0; 153 }