树状数组套主席树[区间动态第k大]

经过我不断地调试(抄代码) 终于过了这个题目=-=
首先由主席树为什么不能维护动态第K大呢
因为静态主席树所有[1, i]的区间在询问前就已经确定了
如果修改了一个位置的值 那么后面所有的区间都要修改 时间复杂度就变成了 O ( n 2 l o g n )
是无法接受的
考虑用更灵活的数据结构而不是数组来维护修改
既然是前缀和当然就选择树状数组(线段树可能也可以)啦
原来我们每个点是维护的[1, i]序列的信息 用树状数组维护的化那么每个点倒他后面 l o g n 个点进行一次 u p d a t e
查询的时候也和静态主席树一样 不过用的是树状数组所包含的区间进行查询
那么就做到了 O ( n l o g 2 n ) 的复杂度 就ojbk了

例题 BZOJ1901(ZOJ上也有这个题并且不是权限题)

模板。具体实现见代码。

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)

using namespace std;

tr1::unordered_map<int, int> id;
const int maxn = 2e4 + 10;
int T, n, q, root[maxn], rel[maxn], a[maxn], tmp[maxn], num;
int Sum2[maxn], Sum1[maxn];

struct Query
{
    int opt, x, y, z, id;
}Q[maxn];

struct Fenwick_Tree_Cover_Chairman_Tree
{
    #define ls(x) (T[x].l)
    #define rs(x) (T[x].r)
    #define mid ((l + r) >> 1)
    int cnt;
    struct node
    {
        int l, r, sum;  
    }T[maxn * 400];
    int lowbit(int x)
    {
        return x & (-x);    
    }
    void build(int &x, int l, int r)
    {
        x = ++ cnt; 
        if(l != r)
        {
            build(ls(x), l, mid);
            build(rs(x), mid + 1, r);
        }
    }
    void update(int &x, int pre, int l, int r, int p, int val)
    {
        T[x = ++ cnt] = T[pre];
        T[x].sum += val;
        if(l != r)
        {
            if(p <= mid)
                update(ls(x), ls(pre), l, mid, p, val);
            else
                update(rs(x), rs(pre), mid + 1, r, p, val); 
        }
    }
    void add(int x, int y, int z)
    {
        for(register int i = x; i <= n; i += lowbit(i))
            update(root[i], root[i], 1, num, y, z);
    }
    int query(int l, int r, int p)
    {
        if(l == r) return l;
        int res = 0;
        For(i, 1, Sum2[0])
            res += T[ls(Sum2[i])].sum;
        For(i, 1, Sum1[0])
            res -= T[ls(Sum1[i])].sum;
        if(res >= p)
        {
            For(i, 1, Sum2[0])
                Sum2[i] = ls(Sum2[i]);
            For(i, 1, Sum1[0])
                Sum1[i] = ls(Sum1[i]);
            return query(l, mid, p);
        }
        else
        {
            For(i, 1, Sum2[0])
                Sum2[i] = rs(Sum2[i]);
            For(i, 1, Sum1[0])
                Sum1[i] = rs(Sum1[i]);
            return query(mid + 1, r, p - res);
        }
    }
}Tree;

int main()
{
#ifndef ONLINE_JUDGE
    freopen("1901.in", "r", stdin);
    freopen("1901.out", "w", stdout);
#endif
    char c;
    scanf("%d%d", &n, &q);  
    For(i, 1, n)
        scanf("%d", &a[i]), tmp[++ num] = a[i];
    For(i, 1, q)
    {
        cin >> c;
        if(c == 'C')
            Q[i].opt = 0, scanf("%d%d", &Q[i].x, &Q[i].z), tmp[++ num] = Q[i].z;
        else
            Q[i].opt = 1, scanf("%d%d%d", &Q[i].x, &Q[i].y, &Q[i].z);       
    }
    sort(tmp + 1, tmp + num + 1);
    num = unique(tmp + 1, tmp + num + 1) - tmp - 1;
    Tree.build(root[0], 1, num);
    //update:这里应该写到For(i, 1, n)的 数据有点水啊...代码错的都过了..
    //For(i, 1, num)
    //  root[i] = root[0];
    For(i, 1, n)
        a[i] = lower_bound(tmp + 1, tmp + num + 1, a[i]) - tmp, Tree.add(i, a[i], 1);
    For(i, 1, q)
    {
        if(Q[i].opt)
        {
            Sum1[0] = Sum2[0] = 0;
            for(register int j = Q[i].y; j; j -= Tree.lowbit(j))
                Sum2[++ Sum2[0]] = root[j];
            for(register int j = Q[i].x - 1; j; j -= Tree.lowbit(j))
                Sum1[++ Sum1[0]] = root[j];
            printf("%d\n", tmp[Tree.query(1, num, Q[i].z)]);
        }
        else
        {
            Tree.add(Q[i].x, a[Q[i].x], -1);    
            a[Q[i].x] = lower_bound(tmp + 1, tmp + num + 1, Q[i].z) - tmp;
            Tree.add(Q[i].x, a[Q[i].x], 1);
        }
    }
    return 0;   
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/81000097