【模板】 带修改主席树

也就是树状数组加线段树

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=5e4+7;
 4 struct node{
 5     int l,r,sum;
 6 }tr[N<<3];
 7 struct quer{
 8     int l,r,k,v,op;
 9 }q[10000+7];
10 int rtn,Ln,Rn;
11 int a[N],b[N],rt[N<<2],L[N<<2],R[N<<2];
12 char s[2];
13 void change(int& o,int l,int r,int p,int val){
14     if(!o) o=++rtn;
15     tr[o].sum+=val;
16     if(l==r) return;
17     int m=(l+r)>>1;
18     if(p<=m) change(tr[o].l,l,m,p,val);
19     else change(tr[o].r,m+1,r,p,val);
20 }
21 int query(int l,int r,int k){
22     if(l==r) return l;
23     int m=(l+r)>>1;
24     int cntl=0,cntr=0;
25     for(int i=1;i<=Ln;++i) cntl+=tr[tr[L[i]].l].sum;
26     for(int i=1;i<=Rn;++i) cntr+=tr[tr[R[i]].l].sum;
27     if(k<=cntr-cntl){
28         for(int i=1;i<=Ln;++i) L[i]=tr[L[i]].l;
29         for(int i=1;i<=Rn;++i) R[i]=tr[R[i]].l;
30         return  query(l,m,k);
31     }
32     for(int i=1;i<=Ln;++i) L[i]=tr[L[i]].r;
33     for(int i=1;i<=Rn;++i) R[i]=tr[R[i]].r;
34     return query(m+1,r,k-cntl-cntr);
35 }
36 int main(){
37     int T;scanf("%d",&T);
38     while(T--){
39         rtn=0;
40         memset(rt,0,sizeof(rt));
41         int numn=0;
42         int n,m;scanf("%d%d",&n,&m);
43         for(int i=1;i<=n;++i) tr[i].sum=0;
44         for(int i=1;i<=n;++i) scanf("%d",&a[i]),b[++numn]=a[i];
45         for(int i=1;i<=m;++i){
46             scanf("%s",s);
47             if(s[0]==‘Q‘){
48                 scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k);
49                 q[i].op=0;
50             }
51             else{
52                 scanf("%d%d",&q[i].l,&q[i].v);
53                 q[i].op=1;
54                 b[++numn]=q[i].v;
55             }
56         }
57         sort(b+1,b+1+numn);
58         int num=unique(b+1,b+1+numn)-b-1;
59         for(int i=1;i<=n;++i){
60             a[i]=lower_bound(b+1,b+1+num,a[i])-b;
61             for(int j=i;j<=n;j+=j&(-j)){
62                 change(rt[j],1,num,a[i],1);
63             }
64         }
65         for(int i=1;i<=m;++i){
66             if(!q[i].op){
67                 Ln=Rn=0;
68                 for(int j=q[i].l-1;j;j-=j&(-j))  L[++Ln]=rt[j];
69                 for(int j=q[i].r;j;j-=j&(-j)) R[++Rn]=rt[j];
70                 printf("%d\n",b[query(1,num,q[i].k)]);
71             }
72             else{
73                 for(int j=q[i].l;j<=n;j+=j&(-j))
74                     change(rt[j],1,num,a[q[i].l],-1);
75                 a[q[i].l]=lower_bound(b+1,b+1+num,q[i].v)-b;
76                for(int j=q[i].l;j<=n;j+=j&(-j)) change(rt[j],1,num,a[q[i].l],1);
77             }
78         }
79     }
80     return 0;
81 }

原文地址:https://www.cnblogs.com/xiaobuxie/p/11391864.html

时间: 2024-10-18 14:27:35

【模板】 带修改主席树的相关文章

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

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

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

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

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条高速光缆组成. 每个部门都有一个专属的路由器,

[BZOJ 4826]影魔 区间修改主席树 标记永久化

为了这道题还特地去学了标记永久化,可能对于区间修改主席树或者树套树比较有用吧OvO 我们可以把答案分为两部分:p1造成的和p2造成的 我们枚举序列,用单调栈求出序列每一个位置i,左右边第一个比它大的L,R 开三棵主席树tree1 tree2 tree3 把L扔进tree1的R位置(单点+1),L+1~i-1扔进tree2的R位置,i+1~R-1扔进tree3的L位置(区间+1) 然后询问[l,r]的时候,求出三棵区间主席树 p1造成的贡献为区间tree1内大于等于L的个数 p2造成的贡献为区间t

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

bzoj2223 [Coci 2009]PATULJCI (模板)(主席树)

2223: [Coci 2009]PATULJCI Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1245  Solved: 530[Submit][Status][Discuss] Description HINT 输入第二个整数是序列中权值的范围Lim,即1<=ai(1<=i<=n)<=Lim,1<=Lim<=10000. 主席树模板dearu: 蒟蒻只能码板子了啊(摊): ↓代码 1 #include<ios

待修改主席树 (树状数组+主席树)

终于学了这个我仰慕已久的算法. 对于待修改的主席树我们只需要多开一维,进行修改后的求和.复杂度进化为O(nlog^2n) 我们需要开R0 L0两个数组记录树状数组的"路径" 然后其他操作就和主席树一样咯! 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=60006; 4 vector<int>v; 5 int n,m,cnt,mx; 6 int R0[N],L0[N],a[N],R[N

BZOJ.2453.维护队列([模板]带修改莫队)

题目链接 带修改莫队: 普通莫队的扩展,依旧从[l,r,t]怎么转移到[l+1,r,t],[l,r+1,t],[l,r,t+1]去考虑 对于当前所在的区间维护一个vis[l~r]=1,在修改值时根据是否在当前区间内修改即可. 块大小取\(O(n^{\frac{2}{3}})\),排序依次按左端点所在块.右端点所在块.修改次数(时间) 复杂度为\(O(n^{\frac{5}{3}})\) (证明在这) #include <cmath> #include <cstdio> #inclu

【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