zoukankan      html  css  js  c++  java
  • 洛谷P2617 Solution

    题目链接

    题解

    动态查询区间k小值——树状数组套主席树( •̀ ω •́ )

    如果直接主席树上进行动态修改,每次需要修改([l,r])区间内所有的根,时间复杂度为(O(nlogn))。主席树是前缀和,树状数组也是前缀和,而且还可以动态修改,巧了你们两个认识一下(

    具体实现:主席树中以(rt_i)为根的子树存储的不再是第(i)个版本(([1,i]))的信息,而是lowbit区间中版本的信息(如同树状数组中的一个节点)。modify:与树状数组相仿,不过修改循环从(x)开始而非(1)(a_x)的修改仅影响([x,n])的前缀和)。query:预处理出需要查询的主席树根(约(logn)个,以lowbit覆盖查询区间),统计左儿子中元素数量与转移时,预处理的每个根都进行一遍即可。

    AC代码

    #include<bits/stdc++.h>
    #define lowb(x) x&(-x)
    using namespace std;
    const int N=1e5+10;
    struct node {char op; int x,y,z;} q[N];
    int rt[N],ls[N*200],rs[N*200],sum[N*200],tmp[2][20],cnt[2];
    //tmp[1/0]:[1,r]/[1,l-1]区间内需要查询的根(节点),cnt[2]:需要查询的根数
    int a[N],b[2*N],nn,n,tot;//b:离散化数组
    void add(int &x,int l,int r,int pos,int v)
    {
    	if(!x) x=++tot;
    	sum[x]+=v;
    	if(l==r) return;
    	int mid=(l+r)/2;
    	if(pos<=mid) add(ls[x],l,mid,pos,v);
    	else add(rs[x],mid+1,r,pos,v);
    }
    void p_add(int x,int v)
    {
    	int k=lower_bound(b+1,b+nn+1,a[x])-b;//a[x]离散化后的值
    	for(int i=x;i<=n;i+=lowb(i)) add(rt[i],1,nn,k,v);
    }
    int ask(int l,int r,int k)
    {
    	if(l==r) return l;
    	int num=0,mid=(l+r)/2;	
    	for(int i=1;i<=cnt[1];i++) num+=sum[ls[tmp[1][i]]];
    	for(int i=1;i<=cnt[0];i++) num-=sum[ls[tmp[0][i]]];
    	if(k<=num) 
    	{
    		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 ask(l,mid,k);
    	}
    	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 ask(mid+1,r,k-num);//!处理右儿子时k不要忘记-num
    }
    int p_ask(int l,int r,int k)
    {
    	memset(tmp,0,sizeof(tmp));
    	cnt[0]=cnt[1]=0;	
    	for(int i=r;i;i-=lowb(i)) tmp[1][++cnt[1]]=rt[i];
    	for(int i=l-1;i;i-=lowb(i)) tmp[0][++cnt[0]]=rt[i];
    	return ask(1,nn,k);
    }
    int main()
    {
    	ios::sync_with_stdio(0); 
    	int m,x,y,z; char op;
    	cin>>n>>m;
    	for(int i=1;i<=n;i++) {cin>>a[i]; b[++nn]=a[i];}
    	for(int i=1;i<=m;i++)
    	{
    		cin>>q[i].op;
    		if(q[i].op=='C') {cin>>q[i].x>>q[i].y; b[++nn]=q[i].y;}
    		else cin>>q[i].x>>q[i].y>>q[i].z;
    	}
    	sort(b+1,b+nn+1); nn=unique(b+1,b+nn+1)-b-1;
    	for(int i=1;i<=n;i++) p_add(i,1);
    	for(int i=1;i<=m;i++)
    	{
    		if(q[i].op=='C') 
    		{
    			p_add(q[i].x,-1); 
    			a[q[i].x]=q[i].y; p_add(q[i].x,1);
    		}
    		else cout<<b[p_ask(q[i].x,q[i].y,q[i].z)]<<endl; 
    	}
    	return 0;
    }
    
  • 相关阅读:
    NOIP2006代码及简析
    设计模式的原则
    UML应用
    关系
    活动图
    状态图
    UML概序
    UML基本图示
    用例
    介绍一个好的英语学习网站!
  • 原文地址:https://www.cnblogs.com/violetholmes/p/14729314.html
Copyright © 2011-2022 走看看