动态求区间K大值(权值线段树)

我们知道我们可以通过主席树来维护静态区间第K大值。我们又知道主席树满足可加性,所以我们可以用树状数组来维护主席树,树状数组的每一个节点都可以开一颗主席树,然后一起做。

我们注意到树状数组的每一棵树都和前一颗树没有关系,so,并不需要可持久化,一个朴素的权值线段树就可以啦。

我们知道普通的线段树是刚开始就把所有的节点都开了,但我们发现并不需要,因为每个点里的操作并不是很多,很大一部分的节点是用不到的,那么我们就可以不开。用Ls 和 Rs 来记左右儿子的地址,随用随开即可。

#include<bits/stdc++.h>
#define N 100005
#define mid ((l+r)>>1)
using namespace std;
inline int lowbit(int x){return x&-x;}
int n,m,sz,totn,totx,toty,a[N],b[N<<1],ca[N],cb[N],cc[N];
int xx[N],yy[N],rt[N],size[100*N],ls[100*N],rs[100*N];
void ins(int l,int r,int x,int q,int v){
    size[x]+=v;
    if (l==r) return;
    if (q<=mid) { if (!ls[x]) ls[x]=++sz; ins(l,mid,ls[x],q,v);
    } else { if (!rs[x]) rs[x]=++sz; ins(mid+1,r,rs[x],q,v);
    }
}
int query(int l,int r,int q){
    if(l==r)return l; int sum=0;
    for(int i=1;i<=totx;i++)sum-=size[ls[xx[i]]];
    for(int i=1;i<=toty;i++)sum+=size[ls[yy[i]]];
    if(q<=sum){
        for(int i=1;i<=totx;i++)xx[i]=ls[xx[i]];
        for(int i=1;i<=toty;i++)yy[i]=ls[yy[i]];
        return query(l,mid,q);
    }
    else{
        for(int i=1;i<=totx;i++)xx[i]=rs[xx[i]];
        for(int i=1;i<=toty;i++)yy[i]=rs[yy[i]];
        return query(mid+1,r,q-sum);
    }
}
void add(int x,int v){
    int k=lower_bound(b+1,b+totn+1,a[x])-b;
    for(int i=x;i<=n;i+=lowbit(i))ins(1,totn,rt[i],k,v);
}
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch==‘-‘)f=-1;}while(ch<‘0‘||ch>‘9‘);
    do{x=x*10+ch-‘0‘;ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘);
    return f*x;
}
int main(){char s[20];
    n=read();m=read();
    for(int i=1;i<=n;i++)a[i]=read(),b[++totn]=a[i];
    for(int i=1;i<=m;i++){
        scanf("%s",s);ca[i]=read();cb[i]=read();
        if(s[0]==‘1‘)cc[i]=read();else b[++totn]=cb[i];
    }
    sort(b+1,b+totn+1);
    totn=unique(b+1,b+totn+1)-b-1;
    for (int i=1;i<=n;i++) rt[i]=i; sz=n;
    for(int i=1;i<=n;i++)add(i,1);
    for(int i=1;i<=m;i++){
        if(cc[i]){
            totx=toty=0;
            for(int j=ca[i]-1;j;j-=lowbit(j))xx[++totx]=rt[j];
            for(int j=cb[i];j;j-=lowbit(j))yy[++toty]=rt[j];
            printf("%d\n",b[query(1,totn,cc[i])]);
        }
        else{add(ca[i],-1);a[ca[i]]=cb[i];add(ca[i],1);}
    }
}

就酱紫。

时间: 2024-08-02 11:11:16

动态求区间K大值(权值线段树)的相关文章

BZOJ 1901: Zju2112 Dynamic Rankings 区间k大 带修改 在线 线段树套平衡树

之前写线段树套splay数组版..写了6.2k..然后弃疗了.现在发现还是很水的..嘎嘎.. zju过不了,超时. upd:才发现zju是多组数据..TLE一版才发现.然后改了,MLE...手写内存池..尼玛终于过了..附zju2112代码于后. bzoj倒是过了,1A的感觉还是很爽的..可是时间不好看..这就是所谓\(O(nlog^3n)\)的复杂度的可怜之处么? 写挂的地方: insert一定要是传地址指针进去. delete时先把地址指针delete掉,最后把是地址指针指向左儿子or右儿子

poj 2886 Who Gets the Most Candies? 线段树动态求第k大的数

题意: n个小孩站一圈,每个小孩拿一个数字,从第k个孩子开始出局,然后下一个出局的孩子是刚刚出局的孩子之前或之后第v个(刚刚出局的孩子的数字是+v则之后v个,-v则之前v个),这样所有孩子终将出局,第p个出局的孩子得f(p)分,f(p)定义为p的因子个数.求分数最高的孩子. 分析: 设顺时针为正方向,关键是模拟出每次出局的孩子是剩下的孩子中的正方向的第几个,设当前要出局的是第k个,然后要求出第k个小孩的下标(pos)以便下一次计算下一个出局的孩子是第几个,这些步骤可用线段树维护. 代码: //p

POJ2985 并查集+线段树 求第k大的数

其实这题之前做过,线段树一直不熟,所以也一直没有搞懂 本题的关键是线段树原始区间代表的是每一种容器(size不同)的数量 比如 刚开始都是互不相关的,所以1的容器有n个 2 3 4...为0个 线段树每个结点的附加信息是该区间的和 本题查找出的代码是关键 比如左右子树分别为sum 27 25 ,则第26大的容器必然在左子树上,继续递归下去,则要在该左子树找 (26-25)大的容器... 通俗讲 本题就是改变点修改 求和变化(附加信息)的情况 只是用k大转化了一下 线段树还是做的太少,近期还要加强

hdu 2665 可持久化线段树求区间第K大值(函数式线段树||主席树)

http://acm.hdu.edu.cn/showproblem.php?pid=2665 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first line is the number of the test cases. For each test case, the first line contain two integer n and m (

zoj 2112 动态区间求第k大

题目大意: 动态单点更新,然后多次询问求区间内第k大 这里单个的主席树不能实现,这里采取的是树状数组套主席树 首先可以想的是将静态主席树先构建好,不去动它,这里空间复杂度就是O(nlogn),这个只要之前做过主席树的入门题的话就都不是问题 然后考虑更新的情况,这里将更新产生的前缀变化保存在树状数组中,那么每次更新都要更新logn棵树状数组上的主席树,每一棵的更新操作都是 logn次的,那么时间复杂度就是nlognlogn的只是可以承受的 之后的询问也是,预处理好用到的树状数组,然后保存到向量中,

背包问题--求第K大值

这算法有毒,一不小心沾上了不死也脱皮! 在背包问题中这个求第K大值就骚扰了我一整天,让我心神不宁,浑身难受- -! 我看到的这种写法是把原本的DP[X]加一维变成DP[X][Y],X用来确定当前背包容量,Y则是Y个值,分别是记录从最大到第K大,(因为只要求K大,所以那些更小的值就不用记录了) 接下来是讨论这个DP[X][Y],可以理解为它是表示的背包容量为X时的第Y大值,而DP[X][ ]可以理解为所有背包容量为X时的值,这样就方便下面的理解了. 在一般背包解决问题中用的01背包公式大约就是DP

HDU 4738——Caocao&#39;s Bridges——————【求割边/桥的最小权值】

Caocao's Bridges Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4738 Description Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. But he wouldn't give up. Caocao's army st

算法导论学习之线性时间求第k小元素+堆思想求前k大元素

对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思路例如以下: 1.分解:将A[p,r]分解成A[p,q-1]和A[q+1,r]两部分.使得A[p,q-1]都小于A[q],A[q+1,r]都不小于A[q]; 2.求解:假设A[q]恰好是第k小元素直接返回,假设第k小元素落在前半区间就到A[p,q-1]递归查找.否则到A[q+1,r]中递归查找. 3

HDU 5249 离线树状数组求第k大+离散化

KPI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1160    Accepted Submission(s): 488 Problem Description 你工作以后, KPI 就是你的全部了. 我开发了一个服务,取得了很大的知名度.数十亿的请求被推到一个大管道后同时服务从管头拉取请求.让我们来定义每个请求都有一个重要值.我的