1. 程式人生 > >bzoj 1058: [ZJOI2007]報表統計【set】

bzoj 1058: [ZJOI2007]報表統計【set】

我想寫FHQtreap的!是set自己跑進程式碼的!因為太好寫了
是有點慢……洛谷上不吸氧會T一個點
就是,用一個set p維護所有點值,ans維護MIN_SORT_GAP的答案,每次insert一個點的時候都查一下它在p裡的前驅後繼,更新一下ans即可;用一個multiset c維護差分後的序列,a[i]表示第i個位置的開頭數字,b[i]表示結尾數字,每次在x位置新插入值v的時候都要c.erase(c.find(abs(a[x+1]-b[x]))),c.insert(abs(a[x+1]-v)),c.insert(abs(v-b[x]))(這個應該很好理解)然後查詢的時候直接找begin即可
差分的時候注意一下邊界
想要快的話大概是線段樹+樹上二分代替p,平衡樹代替set?

#include<iostream>
#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
const int N=500005;
int n,m,a[N],b[N],ans=1e9;
char o[20];
set<int>p;
multiset<int>c;
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>'9'||p<'0')
    {
        if(p=='-')
            f=-1;
        p=getchar();
    }
    while(p>='0'&&p<='9')
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=b[i]=read();
        if(i>1)
        {
            c.insert(abs(a[i]-a[i-1]));
            set<int>::iterator it=p.lower_bound(a[i]);
            if(it!=p.end())
                ans=min(ans,(*it)-a[i]);//,cerr<<a[i]<<" "<<*it<<endl;
            if(it!=p.begin())
                ans=min(ans,a[i]-(*--it));
        }
        p.insert(a[i]);
    }
    while(m--)
    {
        scanf("%s",o+1);
        if(o[1]=='I')
        {
            int x=read(),v=read();
            set<int>::iterator it=p.lower_bound(v);
            if(it!=p.end())
                ans=min(ans,(*it)-v);
            if(it!=p.begin())
                ans=min(ans,v-(*--it));
            p.insert(v);
            if(x<n)
                c.erase(c.find(abs(a[x+1]-b[x]))),c.insert(abs(a[x+1]-v));
            c.insert(abs(v-b[x]));
            b[x]=v;
        }
        else if(o[5]=='G')
            printf("%d\n",*c.begin());
        else
            printf("%d\n",ans);
    }
    return 0;
}