zoj2112--Dynamic Rankings(树状数组+主席树)

题目连接:zoj2112

给出n个点,两种操作,Q:询问在[l,r]内的第k大的数,C:更改第i个数位x

动态的询问第k大,使用树状数组修改和查询前缀和。

因为给出的空间小,所以可以将n个点做成一个静态的主席树,然后对于修改的值,在另一个主席树中修改,查询时同时查询这两个主席树就可以了。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#pragma comment(linker, "/STACK:1024000000,1024000000")
struct node{
    int l , r , num ;
}p[2500000];//所有的节点,p[i].l第i个节点的左儿子的下标,p[i].num第i个节点有的点数
int n , q , cnt ;
int a[50010] , b[10010][3] ;//a为初始的输入,b为操作数
int s[60010] , m ;//离散化的数组,和离散后的个数m
int tree[50010] , S[50010];//tree动态的主席树,使用树状数组修改/查询前缀和,S静态的主席树,保留初始的n个点的前缀和。
int use[50010] ;
int lowbit(int x) {
    return x & -x ;
}
int build(int l,int r) {
    int x = cnt++ , mid = (l+r)/2 ;
    p[x].num = 0 ;
    if( l < r ) {
        p[x].l = build(l,mid) ;
        p[x].r = build(mid+1,r) ;
    }
    return x ;
}
int search1(int x) {
    int low = 0 , mid , high = m-1 ;
    while( low <= high ) {
        mid = (low + high)/2 ;
        if( s[mid] == x ) return mid ;
        else if( s[mid] < x ) low = mid + 1 ;
        else high = mid - 1 ;
    }
}
int update(int y,int k,int num) {
    int root = cnt++ , x = root ;
    int l = 0 , r = m-1 , mid ;
    p[x].num = p[y].num + num ;
    while( l < r ) {
        mid = (l+r)/2 ;
        if( k <= mid ) {
            r = mid ;
            p[x].l = cnt++ ;
            p[x].r = p[y].r ;
            x = p[x].l ;
            y = p[y].l ;
        }
        else {
            l = mid + 1 ;
            p[x].l = p[y].l ;
            p[x].r = cnt++ ;
            x = p[x].r ;
            y = p[y].r ;
        }
        p[x].num = p[y].num + num ;
    }
    return root ;
}
void init() {
    int k , i , j ;
    sort(s,s+m) ;
    m = unique(s,s+m)-s ;
    cnt = 0 ;
    S[0] = build(0,m-1) ;
    for(i = 1 ; i <= n ; i++)
        S[i] = update(S[i-1],search1(a[i]),1) ;
    for(i = 1 ; i <= n ; i++)
        tree[i] = S[0] ;
}
int sum(int i) {
    int sum = 0 ;
    while( i ) {
        sum += p[ p[ use[i] ].l ].num ;
        i -= lowbit(i) ;
    }
    return sum ;
}
void query(int ll,int rr,int k) {
    int num , i , l = 0 , r = m-1 , mid , rt_l = S[ll-1] , rt_r = S[rr] ;
    for(i = ll-1 ; i ; i -= lowbit(i)) use[i] = tree[i] ;
    for(i = rr ; i ; i -= lowbit(i)) use[i] = tree[i] ;
    while( l < r ) {
        num = sum(rr) - sum(ll-1) + p[ p[rt_r].l ].num - p[ p[rt_l].l ].num ;
        mid = (l + r ) / 2 ;
        if( num >= k ) {
            r = mid ;
            for(i = ll-1 ; i ; i -= lowbit(i))
                use[i] = p[ use[i] ].l ;
            for(i = rr ; i ; i -= lowbit(i))
                use[i] = p[ use[i] ].l ;
            rt_l = p[ rt_l ].l ;
            rt_r = p[ rt_r ].l ;
        }
        else {
            l = mid + 1 ;
            k -= num ;
            for(i = ll-1 ; i ; i -= lowbit(i))
                use[i] = p[ use[i] ].r ;
            for(i = rr ; i ; i -= lowbit(i))
                use[i] = p[ use[i] ].r ;
            rt_l = p[ rt_l ].r ;
            rt_r = p[ rt_r ].r ;
        }
    }
    printf("%d\n", s[l]) ;
}
int main() {
    int t , i , j , k1 , k2 ;
    int l , r ;
    char str[10] ;
    scanf("%d", &t) ;
    while( t-- ) {
        scanf("%d %d", &n, &q) ;
        m = 0 ;
        for(i = 1 ; i <= n ; i++) {
            scanf("%d", &a[i]) ;
            s[m++] = a[i] ;
        }
        for(i = 0 ; i < q ; i++) {
            scanf("%s", str) ;
            if( str[0] == 'Q' ) {
                scanf("%d %d %d", &b[i][0], &b[i][1], &b[i][2]) ;
            }
            else {
                b[i][0] = -1 ;
                scanf("%d %d", &b[i][1], &b[i][2]) ;
                s[m++] = b[i][2] ;
            }
        }
        init() ;
        for(i = 0 ; i < q ; i++) {
            if( b[i][0] == -1 ) {
                k1 = search1( a[ b[i][1] ] ) ;
                k2 = search1( b[i][2] ) ;
                for(j = b[i][1] ; j <= n ; j += lowbit(j)) {
                    tree[j] = update(tree[j],k1,-1) ;
                    tree[j] = update(tree[j],k2,1) ;
                }
                a[ b[i][1] ] = b[i][2] ;
            }
            else {
                query(b[i][0],b[i][1],b[i][2]) ;
            }
        }
    }
    return 0 ;
}
时间: 2024-12-25 06:20:57

zoj2112--Dynamic Rankings(树状数组+主席树)的相关文章

【bzoj1146】[CTSC2008]网络管理Network 倍增LCA+dfs序+树状数组+主席树

题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络.该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信. 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略.但是由于路由器老化,在这些

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

【bzoj3744】Gty的妹子序列 分块+树状数组+主席树

题目描述 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成了一个序列,每个妹子有一个美丽度. Bakser神犇与他打算研究一下这个妹子序列,于是Bakser神犇问道:"你知道区间 [l,r]中妹子们美丽度的逆序对数吗?" 蒟蒻Autumn只会离线乱搞啊……但是Bakser神犇说道:"强制在线." 请你帮助一下Autumn吧.

ZOJ 2112 Dynamic Rankings(树状数组+主席树)

The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They have developed a more powerful system such that for N numbers a[1],

hdu_5788_Level Up(树状数组+主席树)

题目链接:hdu_5788_Level Up 题意: 有一棵树,n个节点,每个节点有个能力值A[i],mid[i],mid的值为第i节点的子树的中位数(包括本身),现在让你将其中的一个节点的A值改为1e5,问所有的mid的和最大问多少. 题解: 我们可以知道,如果改变其中一个的A[i],如果A[i]是比他父亲节点的mid小,那么他父亲的此时的中位数就会向后移一位 比如 1 2 3 4 5,第3个点是第2个点的父亲,如果改变了第二个点的A值,那么此时变成了1 3 4 5 1e5,第二个点的父亲的m

待修改主席树 (树状数组+主席树)

终于学了这个我仰慕已久的算法. 对于待修改的主席树我们只需要多开一维,进行修改后的求和.复杂度进化为O(nlog^2n) 我们需要开R0 L0两个数组记录树状数组的"路径" 然后其他操作就和主席树一样咯! 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=60006; 4 vector<int>v; 5 int n,m,cnt,mx; 6 int R0[N],L0[N],a[N],R[N

hdu 1166 树状数组 线段树

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 51177    Accepted Submission(s): 21427 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

【BZOJ】1047: [HAOI2007]理想的正方形(单调队列/~二维rmq+树状数组套树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=1047 树状数组套树状数组真心没用QAQ....首先它不能修改..而不修改的可以用单调队列做掉,而且更快,只有O(n^2).而这货是n^2log^2n的建树...虽然查询是log^2n...但是建树那里就tle了.. 那么说题解... 先orz下,好神.. 我怎么没想到单调队列orz 首先我们维护 行 的单调队列,更新每个点在 列 距离内的最小and最大的值 然后我们维护 列 的单调队列,更新每个点

hdu1394(枚举/树状数组/线段树单点更新&amp;区间求和)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 或 -1, 交换两个不相邻数 a, b, 逆序数 += 两者间大于 a 的个数 - 两者间小于 a 的个数: 所以只要求出初始时的逆序对数,就可以推出其余情况时的逆序对数.对于求初始逆序对数,这里 n 只有 5e3,可以直接暴力 / 树状数组 / 线段树 / 归并排序: 代码: 1.直接暴力 1