洛谷2617 Dynamic Rankings(主席树+树状数组)

动态维护区间第K大
本文介绍了一种使用树状数组套权值线段树的数据结构解决方案,用于动态维护区间内的第K大元素。通过离线离散化处理,实现单点修改和区间查询的高效算法,适用于涉及大量查询和修改的场景。

传送门

【题目分析】

题意相当于动态维护区间第K大。

静态第K大可以直接用主席树解决,对每个点处理出一个权值线段树的前缀和作减即可,然而涉及单点修改,他就咕了,因为不可能一棵一棵的去修改。

因为这个地方是单点修改,区间查询,所以可以想到树状数组这个东东上去。所以这个就变成了一个树状数组套权值线段树,即树状数组每个节点维护一棵权值线段树,区间查询就是合并区间[l,r]的线段树的信息。

考虑时间复杂度,因为先将询问离线离散化,所以一次最坏情况下会合并logm棵树,一棵树的修改复杂度为log,所以复杂度是mlog^2m。

单点修改操作就是将原数删掉,将修改后的数更新到树中。

然后就是注意一下数组的大小。。。。。qwq

【代码~】

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;

int n,q;
int a[MAXN],a1[MAXN*2],top;
int tr1[MAXN],tr2[MAXN],lenx,leny;
int rt[MAXN*500],tot;
struct Tree{
	int l,r;
	int siz;
}tr[MAXN*500];
struct Query{
	int l,r,k;
}que[MAXN];

int Read(){
	int i=0,f=1;
	char c;
	for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
	if(c=='-')
	  f=-1,c=getchar();
	for(;c>='0'&&c<='9';c=getchar())
	  i=(i<<3)+(i<<1)+c-'0';
	return i*f; 
}

void update(int &root,int las,int l,int r,int x,int key){
	root=++tot;
	tr[root]=tr[las];
	tr[root].siz+=key;
	if(l==r)
	  return ;
	int mid=l+r>>1;
	if(x<=mid)
	  update(tr[root].l,tr[las].l,l,mid,x,key);
	else
	  update(tr[root].r,tr[las].r,mid+1,r,x,key);
}

int query(int l,int r,int k){
	if(l==r)
	  return l;
	int s=0;
	for(int i=1;i<=lenx;++i)
	  s-=tr[tr[tr1[i]].l].siz;
	for(int i=1;i<=leny;++i)
	  s+=tr[tr[tr2[i]].l].siz;
	int mid=l+r>>1; 
	if(k<=s){
		for(int i=1;i<=lenx;++i)
		  tr1[i]=tr[tr1[i]].l;
		for(int i=1;i<=leny;++i)
		  tr2[i]=tr[tr2[i]].l;
		return query(l,mid,k);
	}
	else{
		for(int i=1;i<=lenx;++i)
		  tr1[i]=tr[tr1[i]].r;
		for(int i=1;i<=leny;++i)
		  tr2[i]=tr[tr2[i]].r;
		return query(mid+1,r,k-s);
	}
}

int lowbit(int x){
	return x&(-x);
}

void add(int x,int val){
	int pos=lower_bound(a1+1,a1+top+1,a[x])-a1;
	for(int i=x;i<=n;i+=lowbit(i)){
		update(rt[i],rt[i],1,top,pos,val);
	}
}

int main(){
	n=Read(),q=Read();
	for(int i=1;i<=n;++i)
	  a[i]=a1[++top]=Read();
	for(int i=1;i<=q;++i){
		char cz[3];
		scanf("%s",cz);
		if(cz[0]=='C'){
			que[i].l=Read();
			que[i].r=Read();
			que[i].k=0,a1[++top]=que[i].r;	
		}
		else{
			que[i].l=Read();
			que[i].r=Read();
			que[i].k=Read();
		}
	}
	sort(a1+1,a1+top+1);
	top=unique(a1+1,a1+top+1)-a1-1;
	for(int i=1;i<=n;++i){
		add(i,1);
	}
	for(int i=1;i<=q;++i){
		if(que[i].k){
			lenx=0,leny=0;
			for(int j=que[i].r;j;j-=lowbit(j))
			  tr2[++leny]=rt[j];
			for(int j=que[i].l-1;j;j-=lowbit(j))
			  tr1[++lenx]=rt[j];
			cout<<a1[query(1,top,que[i].k)]<<'\n';
		}
		else{
			add(que[i].l,-1);
			a[que[i].l]=que[i].r;
			add(que[i].l,1);
		}
	}
	return 0;
}

 

<think>我们首先需要解决两个问题: 1. 解释代码 `matched_genes <- intersect(g, rownames(cells_rankings))` 的含义。 2. 解决在执行 `cells_AUC <- AUCell_calcAUC(geneSets, cells_rankings, aucMaxRank = nrow(cells_rankings)*0.05)` 时出现的警告信息。 问题1:代码含义 该行代码的目的是取两个字符向量的交集。其中: - `g` 是一个基因集合(字符向量),比如某个通路或基因签名中的基因列表。 - `rownames(cells_rankings)` 是矩阵 `cells_rankings` 的行名,通常代表数据集中存在的基因。 - `intersect()` 函数返回两个向量中共同存在的元素,即既在基因集 `g` 中又在数据集中出现的基因。 - 结果存储在 `matched_genes` 中,用于后续分析。 问题2:警告信息 警告信息:'Using only the first 100 genes (aucMaxRank) to calculate the AUC.' 这个警告来自于 `AUCell` 包的 `AUCell_calcAUC` 函数。根据函数说明,`aucMaxRank` 参数用于设置计算AUC时考虑的最大排名(即基因按表达量排序后,只考虑排名在`aucMaxRank`之前的基因)。默认情况下,`aucMaxRank` 是数据集中每个细胞中排名前5%的基因(即 `nrow(cells_rankings)*0.05`)。但是,这里设置 `aucMaxRank = nrow(cells_rankings)*0.05`,为什么还会出现警告? 警告出现的原因可能是:在计算过程中,实际用于计算AUC的基因数量被限制在了100,而不是我们设置的5%的基因数量。这通常是因为在调用函数时,传入的 `aucMaxRank` 值大于了实际用于计算的最大基因数(即基因集合的大小)。但是,根据警告信息,似乎函数内部使用了100这个数值,这可能是由于以下原因: - `geneSets` 中的某个基因集包含的基因数量很少,导致在计算AUC时,实际匹配到的基因数(即 `matched_genes`)少于 `aucMaxRank` 所要求的数量?但是警告信息指出使用的是100个基因,这个100可能是一个默认值或者内部设定的阈值。 然而,查看 `AUCell` 包的文档(或源代码)可知,`aucMaxRank` 参数指定的是用于计算AUC的最大排名(即排名在 `aucMaxRank` 之前的基因)。如果某个基因集的基因数量小于 `aucMaxRank`,那么实际上我们会使用该基因集的所有基因(因为排名超过基因数量的基因都属于该基因集之外,不影响计算)。但警告信息提示的是“使用前100个基因”,这似乎与参数设置不一致。 另一种可能性:在 `AUCell_calcAUC` 函数中,默认情况下,如果不对 `aucMaxRank` 进行设置,则使用默认值(即每个细胞中排名前5%的基因,最大不超过5000)。但是,我们显式设置了 `aucMaxRank = nrow(cells_rankings)*0.05`,这个值可能小于100?或者大于100?警告信息说使用100,说明这里设置的值可能被覆盖了。 实际上,警告信息可能是在提示:我们设置的 `aucMaxRank` 值大于了实际基因集合的大小。例如,如果某个基因集合只有100个基因,而我们设置的 `aucMaxRank` 要求使用每个细胞中排名前5%的基因(假设有500个基因),那么函数内部会自动使用基因集合的大小(即100)作为实际计算的 `aucMaxRank`。此时,警告信息就会提示:使用100个基因来计算AUC。 因此,这个警告是提示我们,由于基因集合的大小小于我们设置的 `aucMaxRank`,所以实际计算时使用了基因集合的大小(即100)作为 `aucMaxRank`。这里的100只是一个例子,实际警告中会显示实际使用的数量(即该基因集的大小)。但是,警告信息中明确说了“100”,说明这个基因集的大小可能是100?或者函数内部有一个截断? 实际上,我们需要检查: - 基因集合 `geneSets` 中每个基因集的大小(即包含的基因数量)是否小于 `aucMaxRank`(即 `nrow(cells_rankings)*0.05`)? - 如果是,那么函数会自动使用基因集的大小作为 `aucMaxRank`,并给出警告。 所以,这个警告是正常的,不影响计算。它只是告诉我们,由于基因集合的大小较小,我们实际使用的基因数(即基因集合的大小)少于我们设置的阈值(5%的基因数)。如果希望避免这个警告,我们可以: 1. 不设置 `aucMaxRank` 参数,使用默认值(即每个细胞中排名前5%的基因,但不超过5000)。 2. 或者,将 `aucMaxRank` 设置为基因集合的大小(但每个基因集大小可能不同,所以需要分别设置)。 3. 或者,忽略这个警告,因为它并不影响结果,只是提示实际使用的基因数比设置的阈值小。 但是,根据警告信息,它明确指出使用了100个基因,这可能是由于基因集合大小就是100?或者函数内部有一个上限100?但根据文档,这个上限应该是5000(默认)。所以我们需要进一步确认。 实际上,在 `AUCell` 包的文档中提到: - `aucMaxRank`:用来计算AUC的排名阈值(即每个细胞中排名在 `aucMaxRank` 之前的基因)。如果基因集合的大小(即匹配到的基因数量)小于 `aucMaxRank`,则使用基因集合的大小作为阈值(以避免引入过多的噪音)。 因此,警告是正常的,它只是告诉我们实际使用了基因集合的大小(而不是我们设置的5%)作为阈值。这里的100可能是某个基因集的大小为100。我们可以通过以下方式验证: 假设我们的数据集有20000个基因,那么5%就是1000个基因(即每个细胞中排名前1000的基因)。但是,如果某个基因集合只有100个基因,那么函数就会使用100作为阈值(因为即使设置1000,该基因集合也只有100个基因可用)。 如何避免这个警告?我们可以: - 在调用函数之前,过滤掉基因数量过少的基因集合(例如,小于5个基因的基因集通常没有意义,但这里100已经是很大的基因集了,所以警告可以忽略)。 - 或者,使用 `suppressWarnings()` 函数来抑制这个警告(不推荐,除非你确定这个警告不会影响结果)。 另外,我们也可以检查一下基因集合的大小: ```r # 检查geneSets中每个基因集的大小 geneSet_sizes <- sapply(geneSets, function(x) length(intersect(x, rownames(cells_rankings)))) ``` 然后,如果发现大部分基因集的大小都大于 `nrow(cells_rankings)*0.05`,那么就不会有警告。如果小于,则会出现警告。我们可以根据实际情况调整 `aucMaxRank`。 但是,根据 `AUCell` 的推荐,使用每个细胞中排名前5%的基因是一个合理的默认值。因此,我们可以保留这个设置,并接受警告(或者忽略它)。 总结: - 代码 `matched_genes <- intersect(g, rownames(cells_rankings))` 用于获取基因集 `g` 在数据集中存在的基因(交集)。 - 警告是由于基因集合的大小小于 `aucMaxRank` 设置的值,导致实际使用基因集合的大小来计算AUC。这是一个正常的行为,不影响结果。如果想要避免警告,可以调整 `aucMaxRank` 为合适的值,或者忽略该警告。 注意:在引用中,我们并没有直接相关的引用,但是引用[1]提到了基因名称匹配的问题,这与第一个问题中取交集的操作类似[^1]。 因此,我们可以这样回答用户: </think>### R语言代码解释与警告处理 #### 1. `matched_genes <- intersect(g, rownames(cells_rankings))` 含义 这段代码用于**获取两个基因集合的交集**: - `g`:目标基因集合(如某个通路或功能相关的基因列表) - `rownames(cells_rankings)`:表达矩阵的行名(数据集中实际存在的基因) - `intersect()`:返回两个集合中**共同存在的基因** - **生物学意义**:过滤掉数据集中不存在的基因,确保后续分析仅基于有效基因,避免因基因缺失导致计算错误或结果偏差[^1] #### 2. AUCell警告分析及解决方案 当执行: ```r cells_AUC <- AUCell_calcAUC(geneSets, cells_rankings, aucMaxRank = nrow(cells_rankings)*0.05) ``` 出现警告: ⚠️ `Using only the first 100 genes (aucMaxRank) to calculate the AUC.` ##### 原因分析: 1. **参数冲突**: - `aucMaxRank` 显式设置为 `nrow(cells_rankings)*0.05` - 但实际传入的 `geneSets` 中某些基因集的有效基因数 ≤ 100 - 函数自动选择较小值(100)作为实际计算阈值 2. **基因匹配问题**: - `geneSets` 中的基因未完全匹配到 `cells_rankings` 的行名 - 通过 `intersect()` 获得的实际有效基因数较少(类似于引用[1]的名称匹配问题)[^1] ##### 解决方案: **步骤1:检查基因匹配情况** ```r # 计算每个基因集的有效基因数 geneSet_counts <- sapply(geneSets, function(gs) { length(intersect(gs, rownames(cells_rankings))) }) print(summary(geneSet_counts)) ``` **步骤2:动态调整参数** ```r # 根据最小有效基因集调整aucMaxRank min_genes <- min(geneSet_counts) cells_AUC <- AUCell_calcAUC( geneSets, cells_rankings, aucMaxRank = min(min_genes, nrow(cells_rankings)*0.05) # 取较小值 ) ``` **步骤3:处理未匹配基因**(参考引用[1]方法)[^1] ```r # 识别未匹配基因 unmatched_genes <- setdiff(unlist(geneSets), rownames(cells_rankings)) write.csv(unmatched_genes, "unmatched_genes.csv") # 导出检查 # 可手动校正基因标识符(如Symbol转Ensembl ID) corrected_genes <- read.csv("corrected_genes.csv")$gene matched_geneSets <- lapply(geneSets, function(gs) { intersect(c(gs, corrected_genes), rownames(cells_rankings)) }) ``` ##### 补充建议: - 当 `min(geneSet_counts) < 100` 时,需检查: - 基因标识符一致性(如Symbol/Ensembl ID) - 数据集版本匹配(引用基因组版本) - 必要时进行基因别名映射 - 警告不影响计算有效性,但可能降低结果灵敏度
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值