zoukankan      html  css  js  c++  java
  • BZOJ 1901: Zju2112 Dynamic Rankings( 树状数组套主席树 )

    裸的带修改主席树.. 之前用BIT套Splay( http://www.cnblogs.com/JSZX11556/p/4625552.html )A过..但是还是线段树好写...而且快(常数比平衡树小). 时空复杂度是O(Nlog(N)+Mlog^2(N))

    -------------------------------------------------------------------------

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cctype>
     
    using namespace std;
     
    #define H(v) (lower_bound(Hash, Hash + Hn, v) - Hash + 1)
     
    const int maxn = 10009;
     
    int N, Q;
    int seq[maxn];
    int Hash[maxn << 1], Hn;
    int Val, Pos;
     
    inline int read() {
    char c = getchar();
    for(; !isdigit(c); c = getchar());
    int ret = 0;
    for(; isdigit(c); c = getchar())
    ret = ret * 10 + c - '0';
    return ret;
    }
     
    struct Event {
    int l, r, v;
    Event(int _l = 0, int _r = 0, int _v = 0) :
    l(_l), r(_r), v(_v) {
    }
    } q[maxn];
     
    void Init() {
    Hn = 0;
    N = read(), Q = read();
    for(int i = 1; i <= N; i++)
    Hash[Hn++] = (seq[i] = read());
    for(int i = 0; i < Q; i++) {
    char c = getchar();
    for(; c != 'C' && c != 'Q'; c = getchar());
    if(c == 'C') {
    int p = read(), v = read();
    q[i] = Event(-1, p, v);
    Hash[Hn++] = v;
    } else {
    int l = read() - 1, r = read();
    q[i] = Event(l, r, read());
    }
    }
    sort(Hash, Hash + Hn);
    Hn = unique(Hash, Hash + Hn) - Hash;
    }
     
    struct Node {
    Node *lc, *rc;
    int v;
    } pool[5000000], *pt, *Null, *Root[maxn], *V[maxn];
     
    void Init_sgt() {
    pt = pool;
    Null = pt++;
    Null->v = 0;
    Null->lc = Null->rc = Null;
    }
     
    Node* Modify(Node* t, int l, int r) {
    Node* o = pt++;
    o->v = t->v + Val;
    if(l != r) {
    int m = (l + r) >> 1;
    if(Pos <= m) {
    o->lc = Modify(t->lc, l, m);
    o->rc = t->rc;
    } else {
    o->lc = t->lc;
    o->rc = Modify(t->rc, m + 1, r);
    }
    }
    return o;
    }
     
    void Build() {
    Root[0] = Null;
    Val = 1;
    for(int i = 1; i <= N; i++) {
    Pos = seq[i] = H(seq[i]);
    Root[i] = Modify(Root[i - 1], 1, Hn);
    }
    }
     
    Node *L[20], *R[20];
    int Ln, Rn;
     
    void Work() {
    for(int i = 1; i <= Hn; i++)
    V[i] = Null;
    for(int i = 0; i < Q; i++)
    if(~q[i].l) {
    Ln = Rn = 0;
    for(int p = q[i].l; p; p -= p & -p)
    L[Ln++] = V[p];
    for(int p = q[i].r; p; p -= p & -p)
    R[Rn++] = V[p];
    Node *_L = Root[q[i].l], *_R = Root[q[i].r];
    int l = 1, r = Hn;
    while(l < r) {
    int cnt = _R->lc->v - _L->lc->v, m = (l + r) >> 1;
    for(int j = 0; j < Ln; j++)
    cnt -= L[j]->lc->v;
    for(int j = 0; j < Rn; j++)
    cnt += R[j]->lc->v;
    if(cnt >= q[i].v) {
    _L = _L->lc;
    _R = _R->lc;
    for(int j = 0; j < Ln; j++)
    L[j] = L[j]->lc;
    for(int j = 0; j < Rn; j++)
    R[j] = R[j]->lc;
    r = m;
    } else {
    q[i].v -= cnt;
    _L = _L->rc;
    _R = _R->rc;
    for(int j = 0; j < Ln; j++)
    L[j] = L[j]->rc;
    for(int j = 0; j < Rn; j++)
    R[j] = R[j]->rc;
    l = m + 1;
    }
    }
    printf("%d ", Hash[l - 1]);
    } else {
    Pos = seq[q[i].r], Val = -1;
    for(int p = q[i].r; p <= Hn; p += p & -p)
    V[p] = Modify(V[p], 1, Hn);
    Pos = seq[q[i].r] = H(q[i].v), Val = 1;
    for(int p = q[i].r; p <= Hn; p += p & -p)
    V[p] = Modify(V[p], 1, Hn);
    }
    }
     
    int main() {
    Init();
    Init_sgt();
    Build();
    Work();
    return 0;
    }

    ------------------------------------------------------------------------ 

    1901: Zju2112 Dynamic Rankings

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 5988  Solved: 2489
    [Submit][Status][Discuss]

    Description

    给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。

    Input

    对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。

    Output

    Sample Input

    5 3
    3 2 1 4 7
    Q 1 4 3
    C 2 6
    Q 2 5 3

    Sample Output

    3
    6

    HINT

    20%的数据中,m,n≤100; 40%的数据中,m,n≤1000; 100%的数据中,m,n≤10000。

    Source

  • 相关阅读:
    【搜索】【并查集】Codeforces 691D Swaps in Permutation
    【模拟】Codeforces 691C Exponential notation
    【模拟】Codeforces 691B s-palindrome
    【模拟】Codeforces 691A Fashion in Berland
    【贪心】HDU 5783 Divide the Sequence
    【动态规划】HDU 5791 Two
    【中途相遇法】【STL】BAPC2014 K Key to Knowledge (Codeforces GYM 100526)
    【线段树】BAPC2014 E Excellent Engineers (Codeforces GYM 100526)
    【扩展欧几里得】BAPC2014 I Interesting Integers (Codeforces GYM 100526)
    【最大流】BAPC2014 A Avoiding the Apocalypse (Codeforces GYM 100526)
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5120922.html
Copyright © 2011-2022 走看看