BZOJ1058:[ZJOI2007]报表统计——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=1058

https://www.luogu.org/problemnew/show/P1110#sub

实现三种操作:

INSERT i k:在原数列的第i个元素后面添加一个新元素k;如果原数列的第i个元素已经添加了若干元素,则添加在这些元素的最后(见下面的例子)

MIN_GAP:查询相邻两个元素的之间差值(绝对值)的最小值

MIN_SORT_GAP:查询所有元素中最接近的两个元素的差值(绝对值)

显然这三种操作都可以splay做啊,愉快的敲了两个splay……

T!L!E!

(总觉得复杂度是对的,可能改成边插边更新(就像本代码一样)能过)

第三种操作没啥好想法,考虑第二种操作,用线段树维护差值最小值。

插入的元素对后来插这个位置的元素造成的贡献有影响,但之后将永远不会改变,于是暴力更新这个差值。

插入的元素影响了它之后位置的元素的贡献,且会不断改变,于是在线段树更新这个差值即可。

#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1000010;
const int INF=1e9;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
char s[101];
int fa[N],tr[N][2],key[N],id[N];
int b[N],del[N],c[N];
int root,sz;
inline bool get(int x){
    return tr[fa[x]][1]==x;
}
int pre(){
    int now=tr[root][0];
    while(tr[now][1])now=tr[now][1];
    return now;
}
int nxt(){
    int now=tr[root][1];
    while(tr[now][0])now=tr[now][0];
    return now;
}
inline void rotate(int x){
    int y=fa[x],z=fa[y],which=get(x);
    tr[y][which]=tr[x][which^1];fa[tr[y][which]]=y;  
    fa[y]=x;tr[x][which^1]=y;fa[x]=z;
    if(z)tr[z][tr[z][1]==y]=x;
    return;
}
inline void splay(int x){
    int f=fa[x];
    while(f){
        if(fa[f])rotate(get(x)==get(f)?f:x);
        rotate(x);f=fa[x];
    }
    root=x;
    return;
}
inline void insert(int v){
    if(!root){
        sz++;tr[sz][0]=tr[sz][1]=fa[sz]=0;
        key[sz]=v;root=sz;
        return;
    }
    int now=root,f=0;
    while(233){
    f=now;
    now=tr[now][key[now]<=v];
        if(!now){
            sz++;tr[sz][0]=tr[sz][1]=0;
        fa[sz]=f;key[sz]=v;
        tr[f][key[f]<=v]=sz;
            splay(sz);
            break;
        }
    }
    return;
}
void build(int a,int l,int r){
    if(l==r){
    del[a]=abs(b[l]-b[l-1]);
    return;
    }
    int mid=(l+r)>>1;
    build(a*2,l,mid);build(a*2+1,mid+1,r);
    del[a]=min(del[a*2],del[a*2+1]);
}
void ins(int a,int l,int r,int p,int x){
    if(l==r){
    del[a]=x;
    return;
    }
    int mid=(l+r)>>1;
    if(p<=mid)ins(a*2,l,mid,p,x);
    else ins(a*2+1,mid+1,r,p,x);
    del[a]=min(del[a*2],del[a*2+1]);
}
int main(){
    int n=read(),m=read();
    int ans1=INF,ans2=INF;
    b[0]=c[0]=INF;
    for(int i=1;i<=n;i++){
    b[i]=c[i]=read();
    insert(b[i]);
    if(i!=1){
        int pr=pre(),nx=nxt();
        if(pr)ans2=min(ans2,abs(key[pr]-b[i]));
        if(nx)ans2=min(ans2,abs(key[nx]-b[i]));
    }
    }
    build(1,1,n);
    for(int i=1;i<=m;i++){
    scanf("%s",s);
    if(s[0]=='I'){
        int pos=read(),v=read();
        insert(v);
        int pr=pre(),nx=nxt();
        if(pr)ans2=min(ans2,abs(key[pr]-v));
        if(nx)ans2=min(ans2,abs(key[nx]-v));
        ans1=min(ans1,abs(c[pos]-v));
        c[pos]=v;
        if(pos+1<=n)ins(1,1,n,pos+1,abs(b[pos+1]-v));
    }else if(strlen(s)==7){
        printf("%d\n",min(del[1],ans1));
    }else{
        printf("%d\n",ans2);
    }
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-03-29 16:31  luyouqi233  阅读(...)  评论(... 编辑 收藏