zoj2112 Dynamic Rankings 动态区间第k大,树状数组套平衡树

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n,m;
int a[maxn];
char op[5];int L,R,k,p,c;

///---treap
struct Node
{
    int ch[2];
    int r,v;
    int sz;
};Node tr[maxn];int rt[maxn];
int tot1;
int s[maxn],tot2;

int newnode()
{
    int o;
    if(tot2) o=s[tot2--];
    else o=++tot1;
    tr[o].ch[0]=tr[o].ch[1]=-1;
    tr[o].r=rand();tr[o].v=0;
    tr[o].sz=1;
    return o;
}

void up(int o)
{
    tr[o].sz=1;
    if(~tr[o].ch[0]) tr[o].sz+=tr[tr[o].ch[0]].sz;
    if(~tr[o].ch[1]) tr[o].sz+=tr[tr[o].ch[1]].sz;
}

void rot(int &o,int d)
{
    int k=tr[o].ch[d^1];
    tr[o].ch[d^1]=tr[k].ch[d];
    tr[k].ch[d]=o;
    up(o);up(k);
    o=k;
}

void Insert(int &o,int x)
{
    if(o==-1){
        o=newnode();
        tr[o].v=x;
        return;
    }
    int d=x<tr[o].v?0:1;
    Insert(tr[o].ch[d],x);
    if(tr[tr[o].ch[0]].r>tr[o].r) rot(o,d^1);
    up(o);
}

void Remove(int &o,int x)
{
    if(o==-1) return;
    if(tr[o].v==x){
        if(tr[o].ch[0]==-1) s[++tot2]=o,o=tr[o].ch[1];
        else if(tr[o].ch[1]==-1) s[++tot2]=o,o=tr[o].ch[0];
        else{
            int d=tr[tr[o].ch[0]].r>tr[tr[o].ch[1]].r?0:1;
            rot(o,d^1);
            Remove(tr[o].ch[d^1],x);
        }
        if(~o) up(o);
        return;
    }
    if(x<tr[o].v) Remove(tr[o].ch[0],x);
    else Remove(tr[o].ch[1],x);
    if(~o) up(o);
}

int getcnt(int &o,int y)
{
    if(o==-1) return 0;
    if(y<=tr[o].v) return getcnt(tr[o].ch[0],y);
    int ls=tr[o].ch[0]==-1?0:tr[tr[o].ch[0]].sz;
    return ls+1+getcnt(tr[o].ch[1],y);
}

int getcnt2(int &o,int y)
{
    if(o==-1) return 0;
    if(y<tr[o].v) return getcnt(tr[o].ch[0],y);
    int ls=tr[o].ch[0]==-1?0:tr[tr[o].ch[0]].sz;
    return ls+1+getcnt2(tr[o].ch[1],y);
}

///---BIT
int lowbit(int x)
{
    return x&-x;
}

void add(int p,int c)
{
    while(p<=n){
        Insert(rt[p],c);
        p+=lowbit(p);
    }
}

void del(int p,int c)
{
    while(p<=n){
        Remove(rt[p],c);
        p+=lowbit(p);
    }
}

int sum(int p,int y)
{
    int res=0;
    while(p){
        res+=getcnt(rt[p],y);
        p-=lowbit(p);
    }
    return res;
}

int sum2(int p,int y)
{
    int res=0;
    while(p){
        res+=getcnt2(rt[p],y);
        p-=lowbit(p);
    }
    return res;
}

int bin(int L,int R,int l,int r,int k)
{
    while(l<=r){
        int m=(l+r)>>1;
        int cnt=sum(R,m)-sum(L-1,m);
        int cnt2=sum2(R,m)-sum2(L-1,m);
        if(cnt<=k-1&&cnt2>=k) return m;
        if(k>cnt2) l=m+1;
        else r=m-1;
    }
}

void Init()
{
    memset(rt,-1,sizeof(rt));
    tot1=tot2=0;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int T;cin>>T;
    while(T--){
        scanf("%d%d",&n,&m);
        Init();
        REP(i,1,n) scanf("%d",&a[i]);
        REP(i,1,n) add(i,a[i]);
        while(m--){
            scanf("%s",op);
            if(op[0]==‘C‘){
                scanf("%d%d",&p,&c);
                del(p,a[p]);
                add(p,c);
                a[p]=c;
            }
            else{
                scanf("%d%d%d",&L,&R,&k);
                printf("%d\n",bin(L,R,0,INF,k));
            }
        }
    }
    return 0;
}

注意下二分要算两个,小于和小于等于的。。。

然后直接树状数组或线段树套上平衡树就可以了。

时间: 2024-07-30 13:45:29

zoj2112 Dynamic Rankings 动态区间第k大,树状数组套平衡树的相关文章

ZOJ2112--Dynamic Rankings (动态区间第k大)

Dynamic Rankings Time Limit: 10 Seconds      Memory Limit: 32768 KB 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

【BZOJ 1901】【Zju 2112】 Dynamic Rankings 动态K值 树状数组套主席树模板题

达神题解传送门:http://blog.csdn.net/dad3zz/article/details/50638360 说一下我对这个模板的理解: 看到这个方法很容易不知所措,因为动态K值需要套树状数组,而我一开始根本不知道该怎么套,, 学习吧,,, 然后我自己脑补如果不套会如何?后来想到是查询O(logn),修改是O(nlogn),很明显修改的复杂度太大了,为了降低修改的复杂度,我们只得套上树状数组来维护前缀和使它的n的复杂度降低为logn,从而修改的复杂度变为O(log2n).但因为我们套

BZOJ 1901 Zju 2112 Dynamic Rankings 动态维护第k小 树套树

题目大意:动态维护第k小. 思路:线段树套treap,裸题,就是不怎么好写. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 50010 #define INF 1e9 #define LEFT (pos << 1) #define RIGHT (pos << 1|1) #define SIZ

ZOJ 1112 Dynamic Rankings【动态区间第K大,整体二分】

题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112 题意: 求动态区间第K大. 分析: 把修改操作看成删除与增加,对所有操作进行整体二分. 代码: #include<cstdio> #include<iostream> #include<cstring> using namespace std; #define pr(x) cout << #x << &quo

整体二分求动态区间第k大

比树状数组套主席树不知道高到哪里去了,solve(l,r,L,R)就是对于L,R的操作区间的答案都在l,r区间里,然后递归下去 复杂度O(nlognlogn),每个操作会执行logn次就是o(nlogn),带上bit就是loglogn //#pragma GCC optimize(2) //#pragma GCC optimize(3) //#pragma GCC optimize(4) //#pragma GCC optimize("unroll-loops") //#pragma

HDU 5412 CRB and Queries(区间第K大 树套数 按值建树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5412 Problem Description There are N boys in CodeLand. Boy i has his coding skill Ai. CRB wants to know who has the suitable coding skill. So you should treat the following two types of queries. Query 1:

【51nod】 第K大区间2(二分+树状数组)

[51nod] 第K大区间2(二分+树状数组) 第K大区间2 ﹡    LH (命题人) 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 160 定义一个长度为奇数的区间的值为其所包含的的元素的中位数.中位数_百度百科 现给出n个数,求将所有长度为奇数的区间的值排序后,第K大的值为多少. 样例解释: [l,r]表示区间的值 [1]:3 [2]:1 [3]:2 [4]:4 [1,3]:2 [2,4]:2 第三大是2 Input 第一行两个数n和k(1<=n<=100000,k&l

【BZOJ1901】Dynamic Rankings,树状数组套主席树

Time:2016.05.09 Author:xiaoyimi 转载注明出处谢谢 传送门(权限) 题面 1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MB Submit: 6678 Solved: 2777 [Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a

[BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log n). 代码 树状数组套线段树 #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> usin