bzoj 1058 bst

  因为是数列的维护,所以我们可以考虑用splay来维护,每次在x插入的时候就在x+1前面插入就行了,然后用bst来维护两问的答案,但是应该会tle。我们来考虑这个问题的性质,首先因为这个数列没有删除操作,所以每个数插入进去之后就不会出来了,换句话说,就是假设insert(x,y)那么y这个值和前面的那个数可以更新相邻差值的答案,且这个不会因为其他的插入操作而使得这个差值消失(消失值类似(x,y)插入,那么之前在x处插入的点与x+1的差值会消失),所以我们只需要存储每个位置最后插入的数,那么对于一个插入(x,y)我们只需要判断x位置是否插入过值然后讨论就行了。那么对于另一个全局差值的更新我们只需要用bst维护所有插入的数,每插入一个数就找前驱后继来更新答案就行了。因为这个答案是递减的,所以当答案为0的时候不用更新就行了,这样大概可以快3-4s。

  反思:很早的时候用pascal写了splay的,满满的tle,然后转了C++之后用的set和map,快了好多,也好写了好多= =

/**************************************************************
    Problem: 1058
    User: BLADEVIL
    Language: C++
    Result: Accepted
    Time:9924 ms
    Memory:40700 kb
****************************************************************/
 
//By BLADEVIL
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#define maxn 1000010
#define inf (~0U>>1)
 
using namespace std;
 
int n,m,ans;
int a[maxn],b[maxn];
char c[20];
map<int,int>ms;
set<int>bt;
 
void update(int x){
    if (bt.count(x)) {
        ans=0; return;
    }
    set<int>::iterator p=bt.upper_bound(x);
    if (p!=bt.end()) ans=min(ans,abs(*p-x));//,printf("%d->%d ",x,*p);
    --p;
    if (*p!=-inf) ans=min(ans,abs(*p-x));//,printf("%d<-%d",x,*p); printf("
");
    bt.insert(x);
}
 
void insert(int x){
    map<int,int>::iterator p=ms.find(x);
    if (p!=ms.end()) p->second++; else ms.insert(pair<int,int>(x,1));
}
 
void erase(int x){
    map<int,int>::iterator p=ms.find(x);
    if (p->second==1) ms.erase(p); else p->second--;
}
 
void printbt(){
    for (set<int>::iterator p=bt.begin();p!=bt.end();p++) printf("%d ",*p); printf("
");
}
 
void printms(){
    for (map<int,int>::iterator p=ms.begin();p!=ms.end();p++) printf("|%d %d
",p->first,p->second);
}
 
int main(){
    ans=inf; bt.insert(-inf);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    for (int i=1;i<n;i++) insert(abs(a[i]-a[i+1]));
    for (int i=1;i<=n;i++) { 
        if (bt.count(a[i])) {
            ans=0; break;
        }
        update(a[i]);
    }
    //printms(); printbt();
    while (m--){
        scanf("%s",&c);
        if (c[0]=='I'){
            int x,y;
            scanf("%d%d",&x,&y);
            if (x==n){
                if (b[x]) insert(abs(b[x]-y)); else insert(abs(a[x]-y));
            } else {
                if (b[x]){
                    erase(abs(b[x]-a[x+1]));
                    insert(abs(b[x]-y)); insert(abs(a[x+1]-y));
                } else {
                    erase(abs(a[x]-a[x+1]));
                    insert(abs(a[x]-y)); insert(abs(a[x+1]-y));
                }
            }
            b[x]=y;
            if (ans) update(y);
        } else
        if (c[4]=='G') {
            printf("%d
",ms.begin()->first);
        } else printf("%d
",ans);
    }
    return 0;
}
/**************************************************************
    Problem: 1058
    User: BLADEVIL
    Language: Pascal
    Result: Time_Limit_Exceed
****************************************************************/
 
//By BLADEVIL
var
    n, m                    :longint;
    root, sroot             :longint;
    father, size            :array[-1..1000010] of longint;
    tree, a                 :array[-1..1000010] of int64;
    son                     :array[-1..1000010,0..1] of longint;
    numt, t, st             :longint;
    tot                     :longint;
    left, right, b_size     :array[0..4000010] of longint;
    key                     :array[0..4000010] of int64;
    print                   :int64;
     
function abs(x:int64):int64;
begin
    if x<0 then exit(-x) else exit(x);
end;
     
function min(a,b:int64):int64;
begin
    if a>b then min:=b else min:=a;
end;
     
procedure update(x:longint);
begin
    size[x]:=size[son[x][0]]+size[son[x][1]]+1;
end;
     
function build(l,r:longint):longint;
var
    mid                     :longint;
begin
    mid:=(l+r)>>1;
    build:=mid;
    tree[mid]:=a[mid];
    if mid-1>=l then
    begin
        son[mid][0]:=build(l,mid-1);
        father[son[mid][0]]:=mid;
    end;
    if mid+1<=r then
    begin
        son[mid][1]:=build(mid+1,r);
        father[son[mid][1]]:=mid;
    end;
    update(mid);
end;
 
procedure rotate(x,y:longint);
var
    f                       :longint;
begin
    f:=father[x];
    son[f][y]:=son[x][y xor 1];
    father[son[x][y xor 1]]:=f;
    if f=root then root:=x else
        if f=son[father[f]][0] then
            son[father[f]][0]:=x else
        if f=son[father[f]][1] then
            son[father[f]][1]:=x;
    son[x][y xor 1]:=f;
    father[x]:=father[f];
    father[f]:=x;
    update(f);
    update(x);
end;
 
procedure splay(x,y:longint);
var
    u, v                    :longint;
begin
    while father[x]<>y do
    if father[father[x]]=y then
        rotate(x,ord(x=son[father[x]][1])) else
    begin
        if x=son[father[x]][0] then u:=1 else u:=-1;
        if father[x]=son[father[father[x]]][0] then v:=1 else v:=-1;
        if u*v=1 then
        begin
            rotate(father[x],ord(x=son[father[x]][1]));
            rotate(x,ord(x=son[father[x]][1]));
        end else
        begin
            rotate(x,ord(x=son[father[x]][1]));
            rotate(x,ord(x=son[father[x]][1]));
        end;        
    end;
    update(x);
end;
 
function find(x:int64):int64;
var
    t                       :longint;
begin
    t:=root;
    while true do
    begin
        if size[son[t][0]]+1=x then exit(t) else
        if size[son[t][0]]+1>x then t:=son[t][0] else
        begin
            x:=x-(size[son[t][0]]+1);
            t:=son[t][1];
        end;
    end;
end;
 
procedure left_rotate(var t:longint);
var
    k                       :longint;
begin
    k:=right[t];
    right[t]:=left[k];
    left[k]:=t;
    b_size[k]:=b_size[t];
    b_size[t]:=b_size[left[t]]+b_size[right[t]]+1;
    t:=k;
end;
 
procedure right_rotate(var t:longint);
var
    k                       :longint;
begin
    k:=left[t];
    left[t]:=right[k];
    right[k]:=t;
    b_size[k]:=b_size[t];
    b_size[t]:=b_size[left[t]]+b_size[right[t]]+1;
    t:=k;
end;
 
procedure maintain(var t:longint;flag:boolean);
begin
    if not flag then
    begin
        if b_size[left[left[t]]]>b_size[right[t]] then
            right_rotate(t) else
        if b_size[right[left[t]]]>b_size[right[t]] then
        begin
            left_rotate(left[t]);
            right_rotate(t);
        end else exit;
    end else
    begin
        if b_size[right[right[t]]]>b_size[left[t]] then
            left_rotate(t) else
        if b_size[left[right[t]]]>b_size[left[t]] then
        begin
            right_rotate(right[t]);
            left_rotate(t);
        end else exit;
    end;
     
    maintain(left[t],false);
    maintain(right[t],true);
    maintain(t,true);
    maintain(t,false);
end;
 
procedure insert(var t:longint;v:int64);
begin
    if t=0 then
    begin
        inc(tot);
        t:=tot;
        key[t]:=v;
        b_size[t]:=1;
        left[t]:=0;
        right[t]:=0;
    end else
    begin
        b_size[t]:=b_size[t]+1;
        if v<key[t] then insert(left[t],v) else insert(right[t],v);
        maintain(t,v>=key[t]);
    end;
end;
 
function pred(var t:longint;v:int64):int64;
begin
    if t=0 then exit(maxlongint>>1);
    if key[t]>v then pred:=pred(left[t],v) else
    begin
        pred:=pred(right[t],v);
        if pred=maxlongint>>1 then exit(key[t]);
    end;
end;
 
function succ(var t:longint;v:int64):int64;
begin
    if t=0 then exit(maxlongint>>1);
    if key[t]<v then succ:=succ(right[t],v) else
    begin
        succ:=succ(left[t],v);
        if succ=maxlongint>>1 then exit(key[t]);
    end;
end;
 
function delete(var t:longint;v:int64):int64;
begin
    b_size[t]:=b_size[t]-1;
    if (key[t]=v) or (v>key[t]) and (right[t]=0) or (v<key[t]) and (left[t]=0) then
    begin
        delete:=key[t];
        if (left[t]=0) or (right[t]=0) then
            t:=left[t]+right[t] else
            key[t]:=delete(left[t],v+1);
    end else
        if v>=key[t] then delete:=delete(right[t],v) else delete:=delete(left[t],v);
end;
 
procedure change(x:longint;y:int64);
var
    q, p                    :int64;
     
begin
    splay(x,sroot);
    p:=size[son[root][0]];
    p:=find(p);
    splay(p,root);
    delete(t,abs(tree[p]-tree[root]));
    insert(t,abs(y-tree[p]));
    insert(t,abs(y-tree[root]));
    inc(n);
    a[n]:=y;
    tree[n]:=y;
    son[son[root][0]][1]:=n;
    father[n]:=son[root][0];
    size[n]:=1;
    update(son[root][0]);
    update(root);
    p:=pred(numt,y);
    q:=succ(numt,y);
    if p=maxlongint>>1 then insert(st,abs(q-y)) else
        if q=maxlongint>>1 then insert(st,abs(p-y)) else
        insert(st,min(abs(p-y),abs(q-y)));
    insert(numt,y);
end;
 
function mini(var t:longint):int64;
begin
    if left[t]=0 then exit(key[t]) else exit(mini(left[t]));    
end;
 
procedure init;
var
    i                       :longint;
    x, y                    :int64;
begin  
    readln(n,m);
    for i:=1 to n do read(a[i]);
    readln;
    numt:=0;
     
    st:=0;
    for i:=1 to n do
    begin
        x:=succ(numt,a[i]);
        y:=pred(numt,a[i]);
        insert(numt,a[i]);
        if x=maxlongint>>1 then insert(st,abs(y-a[i])) else
        if y=maxlongint>>1 then insert(st,abs(x-a[i])) else
        insert(st,min(abs(x-a[i]),abs(y-a[i])));
    end;
     
    t:=0;
    for i:=1 to n-1 do
        insert(t,abs(a[i+1]-a[i]));
     
    fillchar(son,sizeof(son),255);
    sroot:=-1;
    inc(n);
    root:=build(0,n);
    father[root]:=sroot;
end;
 
procedure main;
var
    i                       :longint;
    s                       :ansistring;
    ch                      :char;
    x                       :longint;
    y                       :int64;
     
begin
    print:=maxlongint>>1;
    for i:=1 to m do
    begin
        read(ch);
        if ch='I' then
        begin
            s:='';
            while ch<>' ' do
            begin
                s:=s+ch;
                read(ch);
            end;
            readln(x,y);
            change(x+1,y);
        end else
        begin
            readln(s);
            if s[4]='S' then
            begin
                if print=0 then
                begin
                    writeln(0);
                end else
                begin
                    if mini(st)<print then print:=mini(st);
                    writeln(print);
                end;
            end else
                writeln(mini(t));
        end;
    end;
end;
 
begin
    init;
    main;
end.
原文地址:https://www.cnblogs.com/BLADEVIL/p/3574366.html