[COGS 257]动态排名系统 树状数组套主席树

主席树就是所谓可持久化线段树。目前只会打区间k值操作。

那么带修改的呢?因为主席树目的上也是搞前缀和,所以类比数组操作,套一个树状数组就可以了。

谨以此纪念此类型树套树入门

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 51000
#include<vector>
#include<algorithm>
int lowbit(int x){
	return x&(-x);
}
int tes;
int n,m,sz,len;
int a[N],root[N];
vector<int> b;
int find(int x){
	return lower_bound(b.begin(),b.end(),x)-b.begin()+1;
}
struct haha{
	int lc,rc,sum;
}tree[N*100];
int ans;
struct xixi{
	int x,y,k;
}cun[N];
int downx[N],downy[N];
void init(){
	memset(tree,0,sizeof(tree));
	memset(cun,0,sizeof(cun));
	b.clear();
	pos(i,0,n+100) a[i]=root[i]=0;
	sz=0;ans=0;len=0;
}
void update(int &rt,int pos,int l,int r,int num){
	if(!rt) rt=++sz;
	if(l==r){
		tree[rt].sum+=num;return;
	}
	int mid=(l+r)>>1;
	if(pos<=mid) update(tree[rt].lc,pos,l,mid,num);
	else update(tree[rt].rc,pos,mid+1,r,num);
	tree[rt].sum=tree[tree[rt].lc].sum+tree[tree[rt].rc].sum;
}
void add(int x,int pos,int num){
	while(x<=n){
		update(root[x],pos,1,len,num);
		x+=lowbit(x);
	}
}
int query(int l,int r,int k){
	if(l==r) return l;
	int mid=(l+r)>>1;
	int sumx(0),sumy(0),t(0);
	pos(i,1,downx[0]) sumx+=tree[tree[downx[i]].lc].sum;
	pos(i,1,downy[0]) sumy+=tree[tree[downy[i]].lc].sum;
	t=sumy-sumx;
	if(t>=k){
		pos(i,1,downx[0]) downx[i]=tree[downx[i]].lc;
		pos(i,1,downy[0]) downy[i]=tree[downy[i]].lc;
		return query(l,mid,k);
	}
	else{
		pos(i,1,downx[0]) downx[i]=tree[downx[i]].rc;
		pos(i,1,downy[0]) downy[i]=tree[downy[i]].rc;
		return query(mid+1,r,k-t);
	}
}
int Query(int x,int y,int k){
	downx[0]=downy[0]=0;
	int tx=x,ty=y;
	while(tx>0){
		downx[++downx[0]]=root[tx];tx-=lowbit(tx);
	}
	while(ty>0){
		downy[++downy[0]]=root[ty];ty-=lowbit(ty);
	}
	return query(1,len,k);
}
int main(){
	scanf("%d",&tes);
	while(tes--){
		scanf("%d%d",&n,&m);
		init();
		pos(i,1,n) scanf("%d",&a[i]),b.push_back(a[i]);
		pos(i,1,m){
			char c;cin>>c;
			int x,y,k;scanf("%d%d",&x,&y);
			cun[i].x=x;cun[i].y=y;
			if(c==‘Q‘){
				scanf("%d",&k);cun[i].k=k;
			}
			else{
				b.push_back(y);
			}
		}
		sort(b.begin(),b.end());
		b.erase(unique(b.begin(),b.end()),b.end());
		len=b.size();
		pos(i,1,n){
			add(i,find(a[i]),1);
		}
		pos(i,1,m){
			int x=cun[i].x,y=cun[i].y,k=cun[i].k;
			if(k){
				ans=Query(x-1,y,k);
				ans=b[ans-1];
				printf("%d\n",ans);
			}
			else{
				add(x,find(a[x]),-1);
				add(x,find(y),1);
				a[x]=y;
			}
		}
	}
	return 0;
}

  

时间: 2024-10-25 13:33:12

[COGS 257]动态排名系统 树状数组套主席树的相关文章

[COGS257]动态排名系统 树状数组套主席树

257. 动态排名系统 时间限制:5 s   内存限制:512 MB [问题描述]给定一个长度为N的已知序列A[i](1<=i<=N),要求维护这个序列,能够支持以下两种操作:1.查询A[i],A[i+1],A[i+2],...,A[j](1<=i<=j<=N)中,升序排列后排名第k的数.2.修改A[i]的值为j.所谓排名第k,指一些数按照升序排列后,第k位的数.例如序列{6,1,9,6,6},排名第3的数是6,排名第5的数是9.[输入格式]第一行包含一个整数D(0<=

[BZOJ 3196] 二逼平衡树 树状数组套主席树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3357  Solved: 1326[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为

关于树状数组套主席树的一些博客

哇仿佛磕了几百年啊; 废话不多说,以下是帮助很大的一些blog: ZOJ 2112 Dynamic Rankings (动态第k大,树状数组套主席树) 主席树全纪录(这个很好) 主席树乱讲(没啥关系,不过有些题目可以刷??) 随笔分类 - 数据结构---主席树(同上) 原文地址:https://www.cnblogs.com/wwtt/p/10099695.html

BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树

[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <string> #include <alg

【BZOJ1901】Dynamic Rankings,树状数组套主席树

Time:2016.05.09 Author:xiaoyimi 转载注明出处谢谢 传送门(权限) 题面 1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MB Submit: 6678 Solved: 2777 [Submit][Status][Discuss] Description 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a

【树状数组套主席树】带修改区间K大数

P2617 Dynamic Rankings 题目描述给定一个含有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,然后读入一系列的指令,包括询问指令和修改指令. 对于每一个询问指令,你必须输出正确的回答. 输入输出格式输入格

【树套树】【树状数组套主席树】

这是你顾第一次写[树套树]!!!!!!!! [原题] 求区间第k小元素,区间可修改 [正解] 如果没有修改的话,就直接写搞个主席树利用前缀和加加减减一下就好了.但是多了个修改,修改以为着从当前修改节点k到往后n-k个树顶所代表的树全部都要修改,这是一件非常操蛋的事情.回想起多年前学数据结构初步的时候,区间批量修改无非就是树状数组or线段树.故我们借用树状数组的轮廓来构建主席树的各树顶. 对树状数组每个节点,我们都当成是主席树的树顶,改树顶所涵盖的区间与树状数组该节点意义相同. [查询]查询区间[

浅谈树状数组套主席树

话说主席树还没写就先写这一篇了\(qwq\) 回顾一下主席树的实现过程:类似查分思想,将线段树的每次修改看做函数式以支持可持久化.因为这样的线段树是可减的. 那么我们维护信息的时候,就要维护每一次新形成的信息.但是我们可以根据前一个信息的基础上进行改动,而不必要去再建一棵树. 所以总而言之,是前缀和的思想. 那么,当需要修改的时候,怎么做呢? 考虑普通的区间操作,当做单点修改的时候,一般用树状数组,线段树和分块.最好实现的就是树状数组. 考虑用树状数组来维护主席树的信息. 树状数组中维护了每一次

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

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