P2617 Dynamic Rankings(带修主席树)

所谓带修主席树,就是用树状数组的方法维护主席树的前缀和

思路

带修主席树的板子

注意数据范围显然要离散化即可

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct Node{
    int sz,lson,rson;
}PT[100100*400];
struct Q{
    char c;
    int l,r,x,val;
}opt[100100];
const int MAXV = 1e9+10;
int Nodecnt,lcnt,rcnt,root[100100],n,m,a[100100],num[200100],nx;
int lroot[100100],rroot[100100];
int lowbit(int x){
    return x&(-x);
}
void update(int L,int R,int &o,int c,int x){
    PT[++Nodecnt]=PT[o];
    o=Nodecnt;
    PT[o].sz+=c;
    if(L==R)
        return;
    int mid=(L+R)>>1;
    if(x<=mid)
        update(L,mid,PT[o].lson,c,x);
    else
        update(mid+1,R,PT[o].rson,c,x);
}
int query(int l,int r,int L,int R,int k){
    lcnt=0,rcnt=0;
    for(int i=L-1;i;i-=lowbit(i))
        lroot[++lcnt]=root[i];
    for(int i=R;i;i-=lowbit(i))
        rroot[++rcnt]=root[i];
    while(l<=r){
        if(l==r)
            return l;
        int lch=0,mid=(l+r)>>1;
        for(int i=1;i<=rcnt;i++)
            lch+=PT[PT[rroot[i]].lson].sz;
        for(int i=1;i<=lcnt;i++)
            lch-=PT[PT[lroot[i]].lson].sz;
        if(k>lch){//to right
            for(int i=1;i<=rcnt;i++)
                rroot[i]=PT[rroot[i]].rson;
            for(int i=1;i<=lcnt;i++)
                lroot[i]=PT[lroot[i]].rson;
            k-=lch;
            l=mid+1;
        }
        else{
            for(int i=1;i<=rcnt;i++)
                rroot[i]=PT[rroot[i]].lson;
            for(int i=1;i<=lcnt;i++)
                lroot[i]=PT[lroot[i]].lson;
            r=mid;
        }
    }
}
void set(int pos,int x,int c){//x-c
    while(pos<=n){
        update(1,nx,root[pos],c,x);
        pos+=lowbit(pos);
    }
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        num[++nx]=a[i];
    }
    for(int i=1;i<=m;i++){
        char c=getchar();
        while(c!='Q'&&c!='C')
            c=getchar();
        if(c=='Q'){
            opt[i].c='Q';
            scanf("%d %d %d",&opt[i].l,&opt[i].r,&opt[i].val);
        }
        else{
            opt[i].c='C';
            scanf("%d %d",&opt[i].val,&opt[i].x);
            num[++nx]=opt[i].x;
        }
    }
    sort(num+1,num+nx+1);
    nx=unique(num+1,num+nx+1)-num-1;
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(num+1,num+nx+1,a[i])-num;
    for(int i=1;i<=m;i++)
        if(opt[i].c=='C')
            opt[i].x=lower_bound(num+1,num+nx+1,opt[i].x)-num;
    for(int i=1;i<=n;i++)
        set(i,a[i],1);
    for(int i=1;i<=m;i++){
        if(opt[i].c=='Q'){
            printf("%d\n",num[query(1,nx,opt[i].l,opt[i].r,opt[i].val)]);
        }
        else{
            set(opt[i].val,a[opt[i].val],-1);
            set(opt[i].val,opt[i].x,1);
            a[opt[i].val]=opt[i].x;
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/dreagonm/p/10105213.html

时间: 2024-07-31 06:15:20

P2617 Dynamic Rankings(带修主席树)的相关文章

【BZOJ-1901】Dynamic Rankings 带修主席树

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 7292  Solved: 3038[Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i

BZOJ 1901 Zju 2112 Dynamic Rankings 带修改主席树

题目大意:给出一个序列,单点修改,询问区间第k大. 思路:如果不带修改,那么划分树就可以解决,但是划分树是静态的树,不支持修改.带修改的主席舒其实就是外层fenwick套内层权值线段树,但是权值线段树必须动态开节点.然后修改的时候就像树状数组修改那样,每次修改logn个权值线段树.查询的时候也一样,返回logn个权值线段树统计的和. 最后为了求区间第k大,还需要二分答案. CODE: #include <cstdio> #include <cstring> #include <

P2617 Dynamic Rankings(主席树+树状数组)

怕是还没有题解,所以先写一篇. 这题就是维护带修改的主席树.首先树套树肯定是能做的,既然树套树能做那么整体二分肯定也是可以的. 由于我并没有使用这两种做法,所以此处不予介绍. 大概描述下主席树的思路: 首先说说怎么搞带修改主席树? 回忆一般的kth问题,我们的主席树求的是前缀和,这样我们在目标区间的左右端点的主席树差分下就能求出kth. 那么我们如何支持修改操作? 考虑到我们之前使用主席树朴素的维护区间前缀和,支持修改的话,只要把前缀和交给擅长它的树状数组维护,主席树只要维护下位置就好. 1 #

少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小

少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小 有一道题(BZOJ 1901)是这样的:n个数,m个询问,询问有两种:修改某个数/询问区间第k小. 不带修改的区间第k小用主席树很好写,不会的同学可以看一下这个. 加上修改怎么做呢?我们可以用数学老师成天讲的类比思想: 可以发现,不修改的区间k小问题中,每加入一个原序列中的数,对应的主席树在上一个的基础上进行修改,而查询的时候用右端点主席树减去左端点左边的主席树.这样的操作就像是维护前缀和:每次加入一个元素的时候,sum[i] =

zoj 2112 Dynamic Rankings 带修改区间第K大 动态主席树

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

P2617 Dynamic Rankings (动态开点权值线段树 + 树状数组)

题意:带修求区间k小 题解:回忆在使用主席树求区间k小时 利用前缀和的思想 既然是前缀和 那么我们可以使用更擅长维护前缀和的树状数组 但是这里每一颗权值线段树就不是带版本的 而是维护数组里i号点的权值信息 所以实际上并不是主席树 每一棵和前面一棵并没有共用结点 对于一次修改操作 我们先删去这个点的原信息 再更新进去 树状数组上的点一起跳 可能看代码比较好理解一点 这个方法限制性也很强 必须离线 #include <bits/stdc++.h> using namespace std; cons

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

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

P2617 Dynamic Rankings

题目链接:https://www.luogu.org/problem/P2617 题目描述 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题.你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令. 对于每一个询问指令,你必

BZOJ 1146: [CTSC2008]网络管理Network [树上带修改主席树]

1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MBSubmit: 3522  Solved: 1041[Submit][Status][Discuss] Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成. 每个部门都有一个专属的路由器,