zoukankan      html  css  js  c++  java
  • HDU

    题意 

      给一个数列,一些询问,问$[l,r]$中第$K$大的元素是哪一个

    题解:

      写法很多,主席树是最常用的一种之一

      除此之外有:划分树,莫队分块,平衡树等

      主席树的定义其实挺模糊,

      一般认为就是可持久化线段树/函数式线段树的这种实现方式

      被用来求区间第$K$大的时候,是可持久化的权值线段树

      主席树的特点就是 $[l,r]$的区间信息可以通过创造的第$r$颗树的减去第$l-1$颗树得到

      具体思路就是:

      将数列的值进行排序,去重

      对于原序列的每一个值,依次插入可持久化的权值线段树,将它所在排序位置权值+1

      在线段树中,每一次插入实际上都会开一颗节点为$log(n)$新的线段树,树根保存为$rt_i$,存有$[1,i]$的区间信息

      然后对于每次询问$[l,r]$,$tree_r - tree_{l-1}$的第$K$个数字即为答案

      *树之间的减法是指,对于每个节点的权值进行相减

      显然$tree_{i+m}-tree_i$最终得到的树与权值,就代表了$[i+1,i+m]$之间插入的元素,也就是区间$[i+1,m]$的权值树,就可以当做数列整体第$K$大解决了

    #include <bits/stdc++.h>
    #define nd seg[now]
    #define ndp seg[pre]
    #define mid ((s+t)>>1)
    using namespace std;
    const int maxn=1e5+10;
    vector<int>pos;
    int casn,n,m,k;
    int num[maxn],rt[maxn],size;
    struct node{
    	int l,r,sum;
    }seg[maxn*20];
    void maketree(int s=1,int t=n,int &now=rt[0]){
    	now=++size;nd={s,t,0};
    	if(s==t) return ;
    	maketree(s,mid,nd.l);maketree(mid+1,t,nd.r);
    }
    void update(int &now,int pre,int k,int s=1,int t=n){
    	now=++size;nd=ndp,nd.sum++;
    	if(s==t) return ;
    	if(k<=mid)update(nd.l,ndp.l,k,s,mid);
    	else update(nd.r,ndp.r,k,mid+1,t);
    }
    int query(int now,int pre,int k,int s=1,int t=n){
    	if(s==t) return s;
    	int sum=seg[ndp.l].sum-seg[nd.l].sum;
    	if(k<=sum) return query(nd.l,ndp.l,k,s,mid);
    	else return query(nd.r,ndp.r,k-sum,mid+1,t);
    }
    int main(){
    	scanf("%d",&casn);
    	while(casn--){
    		scanf("%d%d",&k,&m);
    		pos.clear();
    		size=0;
    		for(int i=1;i<=k;i++){
    			scanf("%d",num+i);
    			pos.push_back(num[i]);
    		}
    		sort(pos.begin(),pos.end());
    		pos.erase(unique(pos.begin(),pos.end()),pos.end());
    		n=pos.size();
    		maketree(1,n,rt[0]);
    		for(int i=1;i<=k;i++){
    			int id=lower_bound(pos.begin(),pos.end(),num[i])-pos.begin()+1;
    			update(rt[i],rt[i-1],id);
    		}
    		while(m--){
    			int a,b,c;
    			scanf("%d%d%d",&a,&b,&c);
    			printf("%d
    ",pos[query(rt[a-1],rt[b],c)-1]);
    		}
    	}
      return 0;
    }

      

  • 相关阅读:
    MySQL 和 Oracle 在 MyBatis 使用中的区别
    nodeppt:网页版 PPT
    在 sql 语句出现 warning 之后,立刻执行 `show warnings;` 就可以看到 warning 提示信息
    MySQL 列,可选择的数据类型(通过sql命令查看:`help create table;`)
    create table 推荐规则
    MySQL 中的变量:系统变量(包括:会话变量、全局变量)、用户变量(包括:局部变量、用户变量)
    MySQL 有用的查询语句
    MySQL 遇到错误集锦
    VARCHAR(N)类型,utf8编码,则N最大值为多少,n表示什么?
    MySQL 的严格模式
  • 原文地址:https://www.cnblogs.com/nervendnig/p/9197142.html
Copyright © 2011-2022 走看看