luoguP1110 [ZJOI2007]报表统计 [Splay]
题目描述
小 Q 的妈妈是一个出纳,经常需要做一些统计报表的工作。今天是妈妈的生日,小 Q 希望可以帮妈妈分担一些工作,作为她的生日礼物之一。
经过仔细观察,小 Q 发现统计一张报表实际上是维护一个非负整数数列,并且进行一些查询操作。
在最开始的时候,有一个长度为 nn 的整数序列 aa,并且有以下三种操作:
INSERT i k
:在原数列的第 ii 个元素后面添加一个新元素 kk;如果原数列的第 ii 个元素已经添加了若干元素,则添加在这些元素的最后(见样例说明)。MIN_GAP
:查询相邻两个元素的之间差值(绝对值)的最小值。MIN_SORT_GAP
:查询所有元素中最接近的两个元素的差值(绝对值)。
于是小 Q 写了一个程序,使得程序可以自动完成这些操作,但是他发现对于一些大的报表他的程序运行得很慢,你能帮助他改进程序么?
输入格式
第一行包含两个整数,分别表示原数列的长度 nn 以及操作的次数 mm。
第二行为 nn 个整数,为初始序列,第 ii 个整数表示 a_iai。
接下来的 mm 行,每行一个操作,即INSERT i k
,MIN_GAP
,MIN_SORT_GAP
中的一种(无多余空格或者空行)。
输出格式
对于每一个 MIN_GAP
和 MIN_SORT_GAP
命令,输出一行答案即可。
输入输出样例
3 5 5 3 1 INSERT 2 9 MIN_SORT_GAP INSERT 2 6 MIN_GAP MIN_SORT_GAP
2 2 1
说明/提示
样例输入输出 1 解释
一开始的序列为 \{5,3,1\}{5,3,1}。
执行操作 INSERT 2 9
将得到 \{5,3,9,1\}{5,3,9,1},此时 MIN_GAP
为 22,MIN_SORT_GAP
为 22。
再执行操作 INSERT 2 6
将得到:\{5,3, 9, 6, 1\}{5,3,9,6,1}。
注意这个时候原序列的第 22 个元素后面已经添加了一个 99,此时添加的 66 应加在 99 的后面。这个时候 MIN_GAP
为 22,MIN_SORT_GAP
为 11。
数据规模与约定
对于全部的测试点,保证 2<=n,m<=5*10^5, 1<=i<=n, 0<=ai,k<=5*10^8
Solution
考虑每做完一次INSERT操作,将MIN_GAP和MIN_SORT_GAP的答案更新。
考虑建立两个数据结构用以维护答案。
1. 建立Splay树,节点值为相邻数的差(绝对值),当进行一次INSERT操作时,需要将被插入的两数的差的节点删掉,再分别加入新数与这两数的差(边界特殊考虑),答案ans1则为这棵树的最小节点,向左儿子寻找即可
2. 建立另一棵Splay树,节点值为各节点的值,每一次插入新的值后根据其与前驱和后继更新答案ans2(注意初始化)
终于复活了ovo!细节写挂,各种神奇过样例,这题贡献了我提交记录的一片红2333
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> using namespace std; #define inf 0x7f7f7f7f #define dbg(x) cout<<#x<<" = "<<x<<endl struct Splay{ int v,num,ch[2],fa; }; const int maxn=500005; int n,m,root[2],cnt[2],ans1,ans2=inf; int head[maxn],tail[maxn]; Splay T[2][maxn*3]; void rot(int flag,int x,int kind){ int y=T[flag][x].fa,z=T[flag][y].fa; T[flag][y].ch[!kind]=T[flag][x].ch[kind]; if(T[flag][x].ch[kind]) T[flag][T[flag][x].ch[kind]].fa=y; T[flag][x].fa=z; if(z) T[flag][z].ch[y==T[flag][z].ch[1]]=x; T[flag][y].fa=x; T[flag][x].ch[kind]=y; } void splay(int flag,int x){ if(x==0) return; while(T[flag][x].fa){ int y=T[flag][x].fa,z=T[flag][y].fa; if(!z) rot(flag,x,T[flag][y].ch[0]==x); else if(T[flag][z].ch[0]==y){ if(T[flag][y].ch[0]==x) rot(flag,y,1),rot(flag,x,1); else rot(flag,x,0),rot(flag,x,1); } else{ if(T[flag][y].ch[1]==x) rot(flag,y,0),rot(flag,x,0); else rot(flag,x,1),rot(flag,x,0); } } root[flag]=x; } void inc(int flag,int x){ int pos=root[flag],fa=0; while(pos&&T[flag][pos].v!=x){ fa=pos; pos=T[flag][pos].ch[x>T[flag][pos].v]; } if(pos) T[flag][pos].num++; else{ pos=++cnt[flag]; T[flag][pos].v=x; T[flag][pos].fa=fa; T[flag][pos].num=1; T[flag][fa].ch[x>T[flag][fa].v]=pos; } splay(flag,pos); } void fin(int flag,int x){ int pos=root[flag]; while(1) if(x<T[flag][pos].v) pos=T[flag][pos].ch[0]; else{ if(x==T[flag][pos].v){ splay(flag,pos); return; } pos=T[flag][pos].ch[1]; } } int ne(int flag,int kind){ int pos=T[flag][root[flag]].ch[kind]; while(T[flag][pos].ch[!kind]) pos=T[flag][pos].ch[!kind]; return pos; } void del(int flag,int x){ fin(flag,x); int rt=root[flag]; if(T[flag][rt].num>1){ T[flag][rt].num--; return; } if(!T[flag][rt].ch[0]&&!T[flag][rt].ch[1]){ rt=0; return; } if(!T[flag][rt].ch[0]){ rt=T[flag][rt].ch[1]; T[flag][rt].fa=0; return; } else if(!T[flag][rt].ch[1]){ rt=T[flag][rt].ch[0]; T[flag][rt].fa=0; return; } int lb=ne(flag,0),oldroot=rt; splay(flag,lb); T[flag][T[flag][oldroot].ch[1]].fa=root[flag]; T[flag][root[flag]].ch[1]=T[flag][oldroot].ch[1]; } int main(){ // freopen("temp.in","r",stdin); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&head[i]); tail[i]=head[i]; } for(int i=1;i<n;i++) inc(0,abs(head[i]-head[i+1])); int pos=root[0]; while(T[0][pos].ch[0]) pos=T[0][pos].ch[0]; ans1=T[0][pos].v; for(int i=1;i<=n;i++) inc(1,head[i]); for(int i=1;i<=n;i++){ splay(1,i); if(T[1][root[1]].num>1) ans2=0; ans2=min(ans2,abs(T[1][root[1]].v-T[1][ne(1,0)].v)); ans2=min(ans2,abs(T[1][root[1]].v-T[1][ne(1,1)].v)); } char opt[10]; int t1,t2; for(int i=0;i<m;i++){ scanf("%s",opt); // insert if(opt[4]=='R'){ scanf("%d%d",&t1,&t2); del(0,abs(tail[t1]-head[t1+1])); inc(0,abs(t2-tail[t1])); inc(0,abs(t2-head[t1+1])); tail[t1]=t2; int pos=root[0]; while(T[0][pos].ch[0]) pos=T[0][pos].ch[0]; ans1=T[0][pos].v; inc(1,t2); if(T[1][root[1]].num>1) ans2=0; ans2=min(ans2,abs(T[1][root[1]].v-T[1][ne(1,0)].v)); ans2=min(ans2,abs(T[1][root[1]].v-T[1][ne(1,1)].v)); } // min_gap else if(opt[4]=='G'){ printf("%d\n",ans1); } // min_sort_gap else{ printf("%d\n",ans2); } } return 0; }