zoj 2112 Dynamic Rankings 动态第k大 线段树套Treap

Dynamic Rankings

Time Limit: 20 Sec

Memory Limit: 256 MB

题目连接

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112

Description

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], a[2], ..., a[N], you can ask it like: what is the k-th smallest number of a[i], a[i+1], ..., a[j]? (For some i<=j, 0<k<=j+1-i that you have given to it). More powerful, you can even change the value of some a[i], and continue to query, all the same.

Your task is to write a program for this computer, which

- Reads N numbers from the input (1 <= N <= 50,000)

- Processes M instructions of the input (1 <= M <= 10,000). These instructions include querying the k-th smallest number of a[i], a[i+1], ..., a[j] and change some a[i] to t.

Input

The first line of the input is a single number X (0 < X <= 4), the number of the test cases of the input. Then X blocks each represent a single test case.

The first line of each block contains two integers N and M, representing N numbers and M instruction. It is followed by N lines. The (i+1)-th line represents the number a[i]. Then M lines that is in the following format

Q i j k or
C i t

It represents to query the k-th number of a[i], a[i+1], ..., a[j] and change some a[i] to t, respectively. It is guaranteed that at any time of the operation. Any number a[i] is a non-negative integer that is less than 1,000,000,000.

There‘re NO breakline between two continuous test cases.

Output

For each querying operation, output one integer to represent the result. (i.e. the k-th smallest number of a[i], a[i+1],..., a[j])

There‘re NO breakline between two continuous test cases.

Sample Input

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

Sample Output

3
6
3
6

HINT

题意

动态第k大

1. Q x y k,查询区间[x,y]第k大的数是啥

2. C x y,把第x个数变成y

题解:

树套树

在每一个区间里面,我们都套入一个Treap/Splay就好了

1操作很简单,暴力进行二分就好了,我们在[L,R]区间所在的Treap里面查询Rank

2操作,在所有这个数所在的区间,我们都删除原来的,再加入新的就好了

代码:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<ctime>
using namespace std;

#define maxn 1000001
int tmp = 0;
////////////////treap
struct Treap
{
    int root[maxn],sz,s[maxn],ls[maxn],rs[maxn],v[maxn],w[maxn],rnd[maxn];
    void init()
    {
        memset(root,0,sizeof(root));
        sz=0;
    }
    void Updata(int k)
    {
        s[k]=s[ls[k]]+s[rs[k]]+w[k];
    }
    void Rturn(int &k)
    {
        int t;
        t=ls[k],ls[k]=rs[t],rs[t]=k,s[t]=s[k];
        Updata(k);k=t;
    }
    void Lturn(int &k)
    {
        int t;
        t=rs[k],rs[k]=ls[t],ls[t]=k,s[t]=s[k];
        Updata(k);k=t;
    }
    void Insert(int &k,int num)
    {
        if(!k)
        {
            k=++sz;s[k]=w[k]=1;ls[k]=rs[k]=0;rnd[k]=rand();
            v[k]=num;return;
        }
        s[k]++;
        if(v[k]==num)w[k]++;
        else if(num<v[k])
        {
            Insert(ls[k],num);
            if(rnd[ls[k]]<rnd[k])
                Rturn(k);
        }
        else
        {
            Insert(rs[k],num);
            if(rnd[rs[k]]<rnd[k])
                Lturn(k);
        }
    }
    void Del(int &k,int num)
    {
        if(v[k]==num)
        {
            if(w[k]>1){
                w[k]--;
                s[k]--;
                return;
            }
            if(ls[k]*rs[k]==0)
                k=ls[k]+rs[k];
            else if(rnd[ls[k]]<rnd[rs[k]])
                Rturn(k),Del(k,num);
            else
                Lturn(k),Del(k,num);
        }
        else if(num<v[k]){
            Del(ls[k],num);
            s[k]--;
        }
        else{
            Del(rs[k],num);
            s[k]--;
        }
    }
    void Find(int k,int num)
    {
        if(!k)return;
        if(v[k]<=num){
            tmp+=s[ls[k]]+w[k];
            Find(rs[k],num);
        }
        else Find(ls[k],num);
    }
}Tr;

/////////////////////

/////////////////////线段树

void Seg_insert(int k,int l,int r,int x,int num)
{
    Tr.Insert(Tr.root[k],num);
    if(l==r)return;
    int mid=(l+r)/2;
    if(x<=mid)Seg_insert(k*2,l,mid,x,num);
    else Seg_insert(k*2+1,mid+1,r,x,num);
}

void Seg_change(int k,int l,int r,int x,int Now,int Pre)
{
    Tr.Del(Tr.root[k],Pre);
    Tr.Insert(Tr.root[k],Now);
    if(l==r)return;
    int mid=(l+r)/2;
    if(x<=mid)Seg_change(k*2,l,mid,x,Now,Pre);
    else Seg_change(k*2+1,mid+1,r,x,Now,Pre);
}
void Seg_query(int k,int l,int r,int L,int R,int num)
{
    if(l==L&&r==R)
    {
        Tr.Find(Tr.root[k],num);
        return;
    }
    int mid = (l+r)/2;
    if(mid>=R)
        Seg_query(k*2,l,mid,L,R,num);
    else if(mid<L)
        Seg_query(k*2+1,mid+1,r,L,R,num);
    else{
        Seg_query(k*2,l,mid,L,mid,num);
        Seg_query(k*2+1,mid+1,r,mid+1,R,num);
    }
}
///////////////////////////
int a[maxn];
int main()
{
    srand(time(NULL));
    int t;scanf("%d",&t);
    while(t--)
    {
        Tr.init();
        int n,m;scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            Seg_insert(1,1,n,i,a[i]);
        }
        char op[10];
        for(int i=1;i<=m;i++)
        {
            scanf("%s",op);
            if(op[0]==‘C‘)
            {
                int x,y;scanf("%d%d",&x,&y);
                Seg_change(1,1,n,x,y,a[x]);
                a[x]=y;
            }
            else
            {
                int x,y,z;scanf("%d%d%d",&x,&y,&z);
                int l = 0,r = 1e9;
                while(l<=r)
                {
                    int mid = (l+r)/2;
                    tmp = 0;Seg_query(1,1,n,x,y,mid);
                    if(tmp>=z)r=mid-1;
                    else l=mid+1;
                }
                printf("%d\n",l);
            }
        }
    }
}
时间: 2024-07-31 14:33:13

zoj 2112 Dynamic Rankings 动态第k大 线段树套Treap的相关文章

zoj 2112 Dynamic Rankings(主席树&amp;动态第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

ZOJ 2112 Dynamic Rankings(主席树の动态kth)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112 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. T

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 2112 Dynamic Rankings 带修改区间第K大 动态主席树

pass 首先,个人觉得把这个数据结构理解成树状数组套主席树是十分不严谨的.主席树的本质是可持久化权值线段树与前缀和思想的结合.而动态主席树是可持久化权值线段树与树状数组思想的结合.并非树套树般的泾渭分明的叠加. 其次,大概讲下对动态主席树的理解.我们静态主席树中,第i个版本维护的是[1,i]的权值线段树,我们利用前缀和的思想,通过y的版本-x的版本得到[x,y]的权值线段树,从而剥离出一颗对应区间的权值线段树.我们考虑在这个情况下,如果需要修改第a[i]的值,那么从i,i+1,i+2.....

ZOJ 2112 Dynamic Rankings(线段树套treap求动态第K大)

题目链接:点击打开链接 思路:我们都知道, treap可以维护整个区间内的数的大小关系, 那么我们在线段树的每个节点上建一棵treap, 那么对于一个n个数的每一个数, 他都会经历logn个结点,所以总的结点数是n * logn. 然后二分答案ans, 询问区间内<=ans的个数来判断二分方向就行了. 一个防止超内存的黑科技:开一个数组做内存池. 细节参见代码: #include <cstdio> #include <cstring> #include <algorit

ZOJ -2112 Dynamic Rankings 主席树 待修改的区间第K大

Dynamic Rankings 带修改的区间第K大其实就是先和静态区间第K大的操作一样.先建立一颗主席树, 然后再在树状数组的每一个节点开线段树(其实也是主席树,共用节点), 每次修改的时候都按照树状数组的方式去修改,并且修改那些地方.查询的时候就是查询原主席树+树状数组的值. 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r&quo

ZOJ 2112 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

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

题意:给定一个区间,求这个区间第k大的数,支持单点修改. 思路:主席树真是个神奇的东西.........速度很快但是也有一个问题就是占用内存的很大,一般来说支持单点修改的主席树套树状数组空间复杂度为O(n*logn*logn), 如果查询较少的话,可以初始的时候用一颗静态主席树,这样空间复杂度可以降为O(n*logn+q*logn*logn),勉强可以过zoj这道题. 这道题看了好久好久才懂...网上题解一般就几句话.......下面是自己的一些理解. 首先静态主席树这个东西其实比较好懂,就是对

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],