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

怕是还没有题解,所以先写一篇。

这题就是维护带修改的主席树。首先树套树肯定是能做的,既然树套树能做那么整体二分肯定也是可以的。

由于我并没有使用这两种做法,所以此处不予介绍。

大概描述下主席树的思路:

首先说说怎么搞带修改主席树?

回忆一般的kth问题,我们的主席树求的是前缀和,这样我们在目标区间的左右端点的主席树差分下就能求出kth。

那么我们如何支持修改操作?

考虑到我们之前使用主席树朴素的维护区间前缀和,支持修改的话,只要把前缀和交给擅长它的树状数组维护,主席树只要维护下位置就好。




 1 #include"bits/stdc++.h"
 2 using namespace std;
 3 #define nn 40000000
 4 #define lowbit(x) ((x)&(-x))
 5
 6 int rt[nn],b[nn],a[nn],ca[nn],cb[nn],cc[nn] ;
 7 int size[nn],xx[nn],yy[nn],l[nn],r[nn];
 8 int n,m;
 9 int totn;
10 int tot,totx,toty;
11
12 inline int read(){
13     int f=1,x=0;char ch;
14     do{ch=getchar();if(ch==‘-‘)f=-1;}while(ch<‘0‘||ch>‘9‘);
15     do{x=x*10+ch-‘0‘;ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘);
16     return f*x;
17 }
18
19
20 void change(int &y,int x,int L,int R,int pos,int v)
21 {
22       y=++tot; size[tot]=size[x]+v,l[tot]=l[x],r[tot]=r[x];
23     if (L==R)return ;
24     int mid = R+L>>1;if (pos<=mid)change(l[tot],l[x],L,mid,pos,v);
25     else change(r[tot],r[x],mid+1,R,pos,v);
26 }
27
28 inline void add(int x,int v)
29 {
30     int k = lower_bound(b+1,b+1+totn,a[x])-b;
31     for (int i=x;i<=n;i+=lowbit(i)) change(rt[i],rt[i],1,totn,k,v);
32 }
33
34 int query(int L,int R,int p)
35 {
36     if (L==R)return R; int sum=0; int mid = L+R>>1;
37     for (int i=1;i<=totx;i++)sum-=size[l[xx[i]]];
38     for (int i=1;i<=toty;i++)sum+=size[l[yy[i]]];
39     if (p<=sum)
40     {
41        for ( int i=1;i<=totx;i++)xx[i]=l[xx[i]];
42        for ( int i=1;i<=toty;i++)yy[i]=l[yy[i]];
43        return query(L,mid,p);
44     }
45      for ( int i=1;i<=totx;i++)xx[i]=r[xx[i]];
46        for ( int i=1;i<=toty;i++)yy[i]=r[yy[i]];
47       return query(mid+1,R,p-sum);
48 }
49
50 int main()
51 {  char s;
52     n=read(),m=read();
53     for (int i=1;i<=n;i++)a[i]=read(),b[++totn]=a[i];
54
55     for (int i=1;i<=m;i++)
56     {
57         cin>>s; if (s==‘Q‘) ca[i]=read(),cb[i]=read(),cc[i]=read();
58         else ca[i]=read(),cb[i]=read(),b[++totn]=cb[i];
59     }
60         sort(b+1,b+1+totn);
61     totn=unique(b+1,b+1+totn)-b-1;
62
63     for ( int i=1;i<=n;i++) add(i,1);
64     for ( int i=1;i<=m;i++)
65     {
66         if (cc[i])
67         {  totx=toty=0;
68             for ( int j=ca[i]-1;j;j-=lowbit(j))xx[++totx]=rt[j];
69             for ( int j=cb[i];j;j-=lowbit(j))yy[++toty]=rt[j];
70             printf("%d\n",b[query(1,totn,cc[i])]);
71         }
72         else
73         {
74             add(ca[i],-1),a[ca[i]]=cb[i],add(ca[i],1);
75         }
76     }
77
78 }

原文地址:https://www.cnblogs.com/zhangbuang/p/10294155.html

时间: 2024-10-09 15:07:11

P2617 Dynamic Rankings(主席树+树状数组)的相关文章

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

bzoj 1901: Zju2112 Dynamic Rankings -- 主席树,树状数组,哈希

1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MB 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]的值,改变后,程序还能针对改 变后的a继续回答上面的问题. Input 第一行有两个正整数n(1≤

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

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

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

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

BZOJ 1901 Dynamic Rankings 主席树

题目大意:可修改的区间第k小 这个主席树卡了我两天...切掉Count On A Tree 之后我就一直认为带修改的主席树是树状数组套可持久化线段树...其实我被误导了... 尼玛带修改的主席树和可持久化线段树毛关系都木有啊!!! 那就是动态的权值线段树啊啊啊啊啊啊啊!!! 好吧这里给不明白主席树的孩纸一些简介: 1.外层树状数组 2.里层线段树 3.线段树动态开节点.仅此而已.和可持久化完全没关系. 4.一个点上的线段树和其他版本毛关系都没有. 5.正常按照普通的树套树往里插就行了. 7.询问

线段树&amp;数状数组

线段树 单点修改,区间查询 #include<bits/stdc++.h> using namespace std; int n,q; long long num[1000010]; struct tree { int l,r; long long sum,max; }t[4000010]; void BuildTree(int,int,int); void Update(int,int,int,int,long long); long long Query(int,int,int,int,i

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,然后读入一系列的指令,包括询问指令和修改指令. 对于每一个询问指令,你必

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

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