【洛谷P1168】中位数(Splay)/(主席树)

Description

给出一个长度为N的非负整数序列A[i],对于所有1 ≤ k ≤ (N + 1) / 2,输出A[1], A[2], …, A[2k - 1]的中位数。即前1,3,5,……个数的中位数。

N ≤ 100000

Solution

这题方法很多,这里介绍splay的打法

求中位数即求第$(k+1)/$2小的数,用splay维护即可,只有2中操作:插入,旋转

在树上记录一个\(c(u)\)表示节点\(u\)的子树有几个节点,用来判断第n小

只要在插入和旋转的时候维护就行了

Code

#include <cstdio>
#include <algorithm>
#define lc(x) T[(x)][0]
#define N 100010

int n,tot,k[N],T[N][2],s[N],rt,fa[N];

void rotate(int p){
    int q=fa[p],y=fa[q],x=(T[q][1]==p);
    T[q][x]=T[p][x^1];fa[T[q][x]]=q;
    T[p][x^1]=q;fa[q]=p;
    fa[p]=y;
    if(y){
        if(T[y][0]==q) T[y][0]=p;
        else if(T[y][1]==q) T[y][1]=p;
    }
    s[p]=s[q];
    s[q]=s[T[q][0]]+s[T[q][1]]+1;//这里维护c(u)
}

void splay(int x){
    for(int y;y=fa[x];rotate(x))
        if(fa[y]) rotate((x==lc(y))==(y==lc(fa[y]))?y:x);
    rt=x;
}

void Insert(int x,int v){
    if(!rt){
        rt=++tot;
        s[rt]=1;
        k[rt]=v;
        return;
    }

    int y;
    while(y){
        y=T[x][k[x]<v];
        if(!y){
            y=++tot;
            k[y]=v;
            T[y][0]=T[y][1]=0;
            fa[y]=x;
            s[x]++;s[tot]++;//c(u)初始化
            T[x][k[x]<v]=y;
            break;
        }
        x=y;
    }
    splay(y);
}

int Find(int x){
    int r=0;
    for(int u=rt;;){
        if(r+s[T[u][0]]+1==x) return k[u];
        if(r+s[T[u][0]]+1<x) r+=s[T[u][0]]+1,u=T[u][1];
        else u=T[u][0];
    }
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        int t;
        scanf("%d",&t);
        Insert(rt,t);
        if(i&1) printf("%d\n",Find((i>>1)+1));
    }
    return 0;
} 

原文地址:https://www.cnblogs.com/void-f/p/8387031.html

时间: 2024-10-07 02:04:40

【洛谷P1168】中位数(Splay)/(主席树)的相关文章

洛谷P1168 中位数 堆

洛谷P1168 中位数   堆 求a[ 1 ] --a[ 1 ] 的中位数 ,a[ 1 ]--a[ 3 ] 的中位数 a[ 1 ]--a[ 5 ] 的中位数 题解1.假设我们已知 a[ 1 ]--a[ i ] 的中位数 (i&1) 此时我们求 a[ 1 ]--a[ i+2 ] 的中位数 那么我们可以把比他大的划到一份中,比他小的划到一份中,如果两份数的个数相同,则其仍然是中位数2.如果不同,比如说 big > small 那我们就把比他大的数 作为中位数 ans 到比中位数小的数中因为原本s

洛谷 P1168 中位数

题目描述 给出一个长度为N的非负整数序列A[i],对于所有1 ≤ k ≤ (N + 1) / 2,输出A[1], A[3], -, A[2k - 1]的中位数.即前1,3,5,--个数的中位数. 输入输出格式 输入格式: 输入文件median.in的第1行为一个正整数N,表示了序列长度. 第2行包含N个非负整数A[i] (A[i] ≤ 10^9). 输出格式: 输出文件median.out包含(N + 1) / 2行,第i行为A[1], A[3], -, A[2i – 1]的中位数. 输入输出样

洛谷—— P1168 中位数

https://www.luogu.org/problem/show?pid=1168 题目描述 给出一个长度为N的非负整数序列A[i],对于所有1 ≤ k ≤ (N + 1) / 2,输出A[1], A[3], …, A[2k - 1]的中位数.[color=red]即[/color]前1,3,5,……个数的中位数. 输入输出格式 输入格式: 输入文件median.in的第1行为一个正整数N,表示了序列长度. 第2行包含N个非负整数A[i] (A[i] ≤ 10^9). 输出格式: 输出文件m

[洛谷P1168]中位数

题目大意:给你n个数,问你前1.3.5...个数的中位数是多少. 解题思路:首先,前一个数的中位数一定是第一个数. 之后,每次都会读进两个数. 我们需要做到,如果两个数都小于原来的中位数,那么现在的中位数变成比它小的最大的数. 反之,如果两个数都大于等于原来的中位数,则变成比它大的最小的数. 如果一个小,一个大于等于,则显然中位数不变. 可以想到用一个大根堆保存“比当前中位数小的数”,用一个小根堆保存“大于等于当前中位数的数”, 然后,对于读进来的两个数,把比当前中位数小的放进大根堆里,大于等于

洛谷 [P3834] 可持久化线段树(主席树)

主席树可以存储线段树的历史状态,空间消耗很大,一般开45n即可 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> #include <queue> #define lson l, mid #define rson mid+1, r #define ll long long using name

洛谷1558 色板游戏 线段树

我先立个Flag 我,这几天,要过1W道线段树题. 题目背景 阿宝上学了,今天老师拿来了一块很长的涂色板. 题目描述 色板长度为L,L是一个正整数,所以我们可以均匀地将它划分成L块1厘米长的小方格.并从左到右标记为1, 2, ... L.现在色板上只有一个颜色,老师告诉阿宝在色板上只能做两件事:1. "C A B C" 指在A到 B 号方格中涂上颜色 C.2. "P A B" 指老师的提问:A到 B号方格中有几种颜色.学校的颜料盒中一共有 T 种颜料.为简便起见,我

[洛谷P1198/BZOJ1012][JSOI2008] 最大数 - 树状数组/线段树?

其实已经学了树状数组和线段树,然而懒得做题,所以至今没写多少博客 Description 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制:L不超过当前数列的长度.(L>=0) 2. 插入操作. 语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾. 限制:n是整数(可能为负数)并且在长整

洛谷 P3384 【模板】树链剖分

题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和 操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z 操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和 输入输出格式 输入格式: 第一行包含4个正整数N.M.R.P,分别表示树的结点个数.操作个数

洛谷 P3368 【模板】树状数组 2

题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k 操作2: 格式:2 x 含义:输出第x个数的值 输出格式: 输出包含若干行整数,即为所有操作2的结