[ZJOI2007]报表统计
作者:互联网
Link
题目描述
- 在原数列第 \(i\) 个后面添加一个新元素 \(k\);如果原数列的第 \(i\) 个元素已经添加了若干元素,则添加在这些元素的最后。
- 查询相邻两个元素的差值的绝对值的最小值。
- 查询所有元素中一堆元素的差值的绝对值的最小值。
解法
第一个操作很好维护,若要在第 \(i\) 个元素后面插值,那么实际需要插入的位置是 \(i+s_i+1\) ,其中 \(s_i\) 表示原数列第 \(i\) 个数及以前的数后面一共插了多少个数。若 \(s_i\) 加一,那么 \(s_{i+1}~s_n\) 都会加一,显然可以用树状数组做。
第三个操作也好维护,建一棵以值为关键字的平衡树即可。每次插入新元素时,查询前驱后继,更新答案。
关键在于第二个操作,一开始我想的和第三个操作一样,再建一棵以位置为关键字的平衡树,查前驱后继更新答案。但这显然是不对的,因为当一个数 \(a\) 插入到 \(b\) 和 \(c\) 中间时,\(b\) 的后继和 \(c\) 的前驱会变,而之前的答案很可能是 \(|b-c|\)。我们换个思路,考虑多维护一些值 \(pre\)、\(nex\)、\(gap\) 分别表示一个数和前驱的差值、和后继的差值、整棵子树中 \(pre\) 和 \(nex\) 的最小值的最小值。当一个数被插入时,有且仅有 \(3\) 个数的前驱和后继发生变化,而对于每个更改,只会修改一条链,所以我们记录一个 \(fa\) ,每次更新完一个节点后都从当前节点跳 \(fa\) 并 \(update\)。最后的答案就是 \(gap[root]\)
inline void update(int id){
sz[id]=1;
gap[id]=min(pre[id],nex[id]);
if(lid) sz[id]+=sz[lid],gap[id]=min(gap[id],gap[lid]),fa[lid]=id;
if(rid) sz[id]+=sz[rid],gap[id]=min(gap[id],gap[rid]),fa[rid]=id;
}
Tips
若平衡树为空,查前驱后继的时候可能会出问题,\(gap\) 的值也可能出问题,故预先插入一个 \(-inf\) 和 \(inf\)。
两颗平衡树可以用 \(struct\) 分开写,这样思路清晰不容易挂。
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 1000007
#define lid s[id][0]
#define rid s[id][1]
#define INF (1<<30)
int n,m;
inline int read(){
int x=0; bool tag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')tag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return tag? x:-x;
}
inline int abs(int x){return x<0? -x:x;}
inline int min(int x,int y){return x<y? x:y;}
struct BIT{
int c[N];
inline int lowbit(int x){return x&(-x);}
inline void add(int x){while(x<=n)c[x]++,x+=lowbit(x);}
inline int query(int x){int ret=0;while(x)ret+=c[x],x-=lowbit(x);return ret;}
}T;
struct FHQ_Pos{
int rt,key[N],s[N][2],val[N],sz[N],cnt,pre[N],nex[N],gap[N],fa[N];
FHQ_Pos(){rt=cnt=0;}
inline void update(int id){
sz[id]=1;
gap[id]=min(pre[id],nex[id]);
if(lid) sz[id]+=sz[lid],gap[id]=min(gap[id],gap[lid]),fa[lid]=id;
if(rid) sz[id]+=sz[rid],gap[id]=min(gap[id],gap[rid]),fa[rid]=id;
}
inline int New(int x){
key[++cnt]=rand();
val[cnt]=x;
s[cnt][0]=s[cnt][1]=0;
sz[cnt]=1;
pre[cnt]=nex[cnt]=gap[cnt]=INF;
fa[cnt]=0;
return cnt;
}
int merge(int x,int y){
if(!x||!y) return x+y;
if(key[x]<key[y]){
s[x][1]=merge(s[x][1],y);
update(x);
return x;
}else{
s[y][0]=merge(x,s[y][0]);
update(y);
return y;
}
}
void split(int id,int k,int &x,int &y){
if(!id) x=y=0;
else{
if(sz[lid]<k) x=id,split(rid,k-sz[lid]-1,rid,y);
else y=id,split(lid,k,x,lid);
update(id);
}
}
int kth(int id,int k){
while(1){
if(sz[lid]>=k) id=lid;
else if(sz[lid]+1==k) return id;
else k-=sz[lid]+1,id=rid;
}
}
void print(int id){
if(lid) print(lid);
printf("%d ",val[id]);
if(rid) print(rid);
}
}A;
struct FHQ_Val{
int rt,key[N],s[N][2],val[N],sz[N],cnt;
FHQ_Val(){rt=cnt=0;}
inline void update(int id){sz[id]=sz[lid]+sz[rid]+1;}
inline int New(int x){
key[++cnt]=rand();
val[cnt]=x;
s[cnt][0]=s[cnt][1]=0;
sz[cnt]=1;
return cnt;
}
int merge(int x,int y){
if(!x||!y) return x+y;
if(key[x]<key[y]){
s[x][1]=merge(s[x][1],y);
update(x);
return x;
}else{
s[y][0]=merge(x,s[y][0]);
update(y);
return y;
}
}
void split(int id,int k,int &x,int &y){
if(!id) x=y=0;
else{
if(val[id]<=k) x=id,split(rid,k,rid,y);
else y=id,split(lid,k,x,lid);
update(id);
}
}
int kth(int id,int k){
while(1){
if(sz[lid]>=k) id=lid;
else if(sz[lid]+1==k) return id;
else k-=sz[lid]+1,id=rid;
}
}
void print(int id){
if(lid) print(lid);
printf("%d ",val[id]);
if(rid) print(rid);
}
}B;
int sort_gap=INF;
inline void update(int id){
int now=id;
while(now) A.update(now),now=A.fa[now];
}
int main(){
// freopen("data.in","r",stdin);
// freopen("mine.out","w",stdout);
srand(time(NULL));
n=read(),m=read();
A.rt=A.New(-INF);
B.rt=B.merge(B.New(-INF),B.New(INF));
int x,y,z,w;
for(int i=1;i<=n;i++){
int v=read();
int t=A.New(v);
T.add(i);
int val=abs(A.val[A.cnt-1]-v);
A.nex[A.cnt-1]=A.pre[t]=val;
update(A.cnt-1);
A.rt=A.merge(A.rt,t);
// printf("A: ");
// A.print(A.rt);
// putchar('\n');
B.split(B.rt,v,x,y);
int pr=B.val[B.kth(x,B.sz[x])];
int ne=B.val[B.kth(y,1)];
sort_gap=min(sort_gap,abs(v-pr));
sort_gap=min(sort_gap,abs(v-ne));
B.rt=B.merge(B.merge(x,B.New(v)),y);
// printf("B: ");
// B.print(B.rt);
// putchar('\n');
}
A.rt=A.merge(A.rt,A.New(INF));
char op[10]={0};
for(int i=1;i<=m;i++){
scanf("%s",op);
if(op[0]=='I'){
int pos=read(),v=read();
int t=A.New(v);
T.add(pos);
pos=T.query(pos);
A.split(A.rt,pos,x,y);
int pre=A.kth(x,A.sz[x]);
A.nex[pre]=A.pre[t]=abs(A.val[pre]-v);
update(pre);
int nex=A.kth(y,1);
A.pre[nex]=A.nex[t]=abs(A.val[nex]-v);
update(nex);
A.rt=A.merge(A.merge(x,t),y);
// printf("A: ");
// A.print(A.rt);
// putchar('\n');
B.split(B.rt,v,x,y);
pre=B.val[B.kth(x,B.sz[x])];
nex=B.val[B.kth(y,1)];
sort_gap=min(sort_gap,abs(v-pre));
sort_gap=min(sort_gap,abs(v-nex));
B.rt=B.merge(B.merge(x,B.New(v)),y);
// printf("B: ");
// B.print(B.rt);
// putchar('\n');
}else if(op[4]=='G') printf("%d\n",A.gap[A.rt]);
else printf("%d\n",sort_gap);
}
}
/*
3 5
5 3 1
INSERT 2 9
MIN_SORT_GAP
INSERT 2 6
MIN_GAP
MIN_SORT_GAP
*/
标签:lid,sz,报表,int,gap,ZJOI2007,rid,id,统计 来源: https://www.cnblogs.com/wwlwQWQ/p/13882422.html