• 【洛谷P2617】Dynamic Rankings


    题目大意:维护带修改区间 K 小值。

    题解:学习到了树状数组套权值线段树。
    主席树,即:可持久化权值线段树,支持维护静态区间的 K 小值问题,其核心思想是维护 N 棵权值线段树,每个线段树维护的是序列 [1,i] 的权值,并根据可持久化思想使得空间复杂度维持在 (O(nlogn))
    树状数组套权值线段树,支持维护带修改区间 K 小值的问题,其核心思想是改变静态主席树中各个权值线段树的前缀和处理方式,在这里采用树状数组中的前缀和处理方式,平衡了修改和查询的时间和空间。时间和空间复杂度为 (O(nlognlogn))。注意:这里 log 是以 2 为底的对数。1e5 的 log2 大约为16,因此内存开 300 倍。

    代码如下

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    
    inline int read(){
    	int x=0,f=1;char ch;
    	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
    	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
    	return f*x;
    }
    
    char opt[5];
    int n,m,a[maxn],tmp[2][20],cnt[2];
    int d[maxn<<1],len;
    struct operation{bool tag;int l,r,k;int pos,val;}q[maxn];
    struct node{
    	#define ls(x) t[x].lc
    	#define rs(x) t[x].rc
    	int lc,rc,sum;
    }t[maxn*300];
    int tot,root[maxn];
    inline void pushup(int o){t[o].sum=t[ls(o)].sum+t[rs(o)].sum;}
    void insert(int &o,int l,int r,int pos,int val){
    	if(!o)o=++tot;
    	if(l==r){t[o].sum+=val;return;}
    	int mid=l+r>>1;
    	if(pos<=mid)insert(ls(o),l,mid,pos,val);
    	else insert(rs(o),mid+1,r,pos,val);
    	pushup(o);
    }
    int query(int l,int r,int k){
    	if(l==r)return l;
    	int mid=l+r>>1;
    	int lsize=0;
    	for(int i=1;i<=cnt[1];i++)lsize+=t[ls(tmp[1][i])].sum;
    	for(int i=1;i<=cnt[0];i++)lsize-=t[ls(tmp[0][i])].sum;
    	if(k<=lsize){
    		for(int i=1;i<=cnt[1];i++)tmp[1][i]=ls(tmp[1][i]);
    		for(int i=1;i<=cnt[0];i++)tmp[0][i]=ls(tmp[0][i]);
    		return query(l,mid,k);
    	}else{
    		for(int i=1;i<=cnt[1];i++)tmp[1][i]=rs(tmp[1][i]);
    		for(int i=1;i<=cnt[0];i++)tmp[0][i]=rs(tmp[0][i]);
    		return query(mid+1,r,k-lsize);
    	}
    }
    inline int lowbit(int x){return x&-x;}
    inline void add(int x,int val){
    	int pos=lower_bound(d+1,d+len+1,a[x])-d;
    	for(int i=x;i<=n;i+=lowbit(i))insert(root[i],1,len,pos,val);
    }
    int querykth(int l,int r,int k){
    	memset(tmp,0,sizeof(tmp)),cnt[1]=cnt[0]=0;
    	for(int i=r;i;i-=lowbit(i))tmp[1][++cnt[1]]=root[i];
    	for(int i=l-1;i;i-=lowbit(i))tmp[0][++cnt[0]]=root[i];
    	return query(1,len,k);
    }
    
    void read_and_parse(){
    	n=read(),m=read();
    	for(int i=1;i<=n;i++)d[++len]=a[i]=read();
    	for(int i=1;i<=m;i++){
    		scanf("%s",opt);
    		if(opt[0]=='Q')q[i].tag=0,q[i].l=read(),q[i].r=read(),q[i].k=read();
    		else q[i].tag=1,q[i].pos=read(),d[++len]=q[i].val=read();
    	}
    	sort(d+1,d+len+1);
    	len=unique(d+1,d+len+1)-d-1;
    	for(int i=1;i<=n;i++)add(i,1);
    }
    
    void solve(){
    	for(int i=1;i<=m;i++){
    		if(q[i].tag){
    			add(q[i].pos,-1);
    			a[q[i].pos]=q[i].val;
    			add(q[i].pos,1);
    		}else{
    			printf("%d
    ",d[querykth(q[i].l,q[i].r,q[i].k)]);
    		}
    	}
    }
    
    int main(){
    	read_and_parse();
    	solve();
    	return 0;
    }
    
  • 相关阅读:
    express开发实例
    node.js操作mongoDB数据库
    Mysql JDBC Url参数说明useUnicode=true&characterEncoding=UTF-8
    Hibernate 使用说明
    mysql 时间戳与日期格式的相互转换
    MOOC即Massive Open Online Course的缩写
    CentOS+Apache+php无法访问redis的解决方法
    CentOS 6.5下Redis安装详细步骤
    Linux进程基础
    CentOS如何查看端口是被哪个应用/进程占用
  • 原文地址:https://www.cnblogs.com/wzj-xhjbk/p/10463097.html
Copyright © 2020-2023  润新知