zoukankan      html  css  js  c++  java
  • 【BZOJ】1058: [ZJOI2007]报表统计(splay+set)

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

    当复习一下splay。。。。

    做法很简单。。。。。

    观察得知每一次插入一个点只需要维护前后的绝对值

    观察得知min_sort_gap直接二分已经排好序的数组找到前驱后继更新即可(这里是个贪心,显然成立)

    观察得知这是区间操作,所以我用了splayQAQ

    注意些细节即可。

    好慢啊,,10000ms。。。

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <set>
    #include <map>
    using namespace std;
    typedef long long ll;
    #define pii pair<int, int>
    #define mkpii make_pair<int, int>
    #define pdi pair<double, int>
    #define mkpdi make_pair<double, int>
    #define pli pair<ll, int>
    #define mkpli make_pair<ll, int>
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getint()
    #define print(a) printf("%d", a)
    #define dbg(x) cout << (#x) << " = " << (x) << endl
    #define error(x) (!(x)?puts("error"):0)
    #define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }
    #define printarr1(a, b) for1(_, 1, b) cout << a[_] << '	'; cout << endl
    inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    inline const int max(const int &a, const int &b) { return a>b?a:b; }
    inline const int min(const int &a, const int &b) { return a<b?a:b; }
    
    const int N=500005, oo=~0u>>2;
    set<int> s;
    int b[N], n, m, ans2=oo, cnt;
    struct node *null;
    struct node {
        node *ch[2], *fa;
        int mn, w, s, v;
        node() { ch[0]=ch[1]=fa=null; mn=oo; w=oo; s=1; v=oo; }
        void pushup() { mn=w; mn=min(mn, min(ch[0]->mn, ch[1]->mn)); s=1+ch[0]->s+ch[1]->s; }
        bool d() { return fa->ch[1]==this; }
        void setc(node *c, bool d) { c->fa=this; ch[d]=c; }
    }*root, *arr[N];
    void rot(node *x) {
        node *fa=x->fa; bool d=x->d();
        fa->fa->setc(x, fa->d());
        fa->setc(x->ch[!d], d);
        x->setc(fa, !d);
        fa->pushup();
        if(fa==root) root=x;
    }
    void splay(node *x, node *fa=null) {
        while(x->fa!=fa)
            if(x->fa->fa==fa) rot(x);
            else x->d()==x->fa->d()?(rot(x->fa), rot(x)):(rot(x), rot(x));
        x->pushup();
    }
    node *sel(node *x, int k) {
        if(x==null) return null;
        int s=x->ch[0]->s;
        if(k==s) return x;
        if(k>s) return sel(x->ch[1], k-s-1); else return sel(x->ch[0], k);
    }
    node *getpos(int pos) {
        splay(sel(root, pos));
        splay(sel(root, pos+1), root);
        return root->ch[1];
    }
    void fix(int pos, int v, const bool flag) {
        node *fa=getpos(pos);
        node *c=new node;
        c->v=v; 
        if(fa->ch[1]!=null) c->w=abs(v-fa->v);
        fa->setc(c, 0);
        if(root->ch[0]!=null) root->w=abs(root->v-v);
        if(flag) { arr[++cnt]=c; }
        splay(c); 
    }
    void work1() { printf("%d
    ", root->mn); }
    void work2() { printf("%d
    ", ans2); }
    void maintain(const int &b) {
        set<int>::iterator it=s.lower_bound(b);
        ans2=min(ans2, abs(*it-b)); --it;
        ans2=min(ans2, abs(*it-b));
        s.insert(b);
    }
    void insert() {
        int x=getint(), y=getint();
        maintain(y);
        node *it=arr[x];
        splay(it);
        fix(it->ch[0]->s+b[x], y, 0);
        ++b[x];
    }
    void build() {
        int t;
        for1(i, 1, n) {
            read(t);
            maintain(t);
            fix(i-1, t, 1);
        }
    }
    void init() {
        s.insert(oo);
        s.insert(-oo);
        null=new node;
        null->ch[0]=null->ch[1]=null->fa=null; null->s=0;
        root=new node;
        node *c=new node;
        root->setc(c, 1);
    }
    void pri(node *x=root) {
        if(x==null) return;
        pri(x->ch[0]);
        printf("%d ", x->v);
        pri(x->ch[1]);
    }
    int main() {
        read(n); read(m);
        init();
        build();
        char od[20];
        for1(i, 1, m) {
            scanf("%s", od+1);
            if(od[5]=='R') insert();
            else if(od[5]=='G') work1();
            else if(od[5]=='S') work2();
        }
        //pri();
        return 0;
    }
    

      


    Description

    小Q的妈妈是一个出纳,经常需要做一些统计报表的工作。今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一。经过仔细观察,小Q发现统计一张报表实际上是维护一个可能为负数的整数数列,并且进行一些查询操作。在最开始的时候,有一个长度为N的整数序列,并且有以下三种操作: INSERT i k 在原数列的第i个元素后面添加一个新元素k; 如果原数列的第i个元素已经添加了若干元素,则添加在这些元素的最后(见下面的例子) MIN_GAP 查询相邻两个元素的之间差值(绝对值)的最小值 MIN_SORT_GAP 查询所有元素中最接近的两个元素的差值(绝对值) 例如一开始的序列为 5 3 1 执行操作INSERT 2 9将得到: 5 3 9 1 此时MIN_GAP为2,MIN_SORT_GAP为2。 再执行操作INSERT 2 6将得到: 5 3 9 6 1 注意这个时候原序列的第2个元素后面已经添加了一个9,此时添加的6应加在9的后面。这个时候MIN_GAP为2,MIN_SORT_GAP为1。于是小Q写了一个程序,使得程序可以自动完成这些操作,但是他发现对于一些大的报表他的程序运行得很慢,你能帮助他改进程序么?

    Input

    第一行包含两个整数N,M,分别表示原数列的长度以及操作的次数。第二行为N个整数,为初始序列。接下来的M行每行一个操作,即“INSERT i k”,“MIN_GAP”,“MIN_SORT_GAP”中的一种(无多余空格或者空行)。

    Output

    对于每一个“MIN_GAP”和“MIN_SORT_GAP”命令,输出一行答案即可。

    Sample Input

    3 5
    5 3 1
    INSERT 2 9
    MIN_SORT_GAP
    INSERT 2 6
    MIN_GAP
    MIN_SORT_GAP

    Sample Output

    2
    2
    1

    HINT

    对于100%的数据,N , M ≤500000 对于所有的数据,序列内的整数不超过5*10^8。

    Source

  • 相关阅读:
    冒泡排序
    获取某年某月有多少天 & 常用日期转换
    left join,right join ,inner join
    Left join加上where条件的困惑
    ORACLE查询练习
    Ch25 文件和注册表操作(2)-- 读写文件
    Ch25 文件和注册表操作(1)--文件系统
    C#入门经典札记_Ch05变量的更多内容
    C#入门经典札记_Ch04流程控制
    C#入门经典札记_Ch03变量和表达式
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4104708.html
Copyright © 2011-2022 走看看