zoukankan      html  css  js  c++  java
  • P3380 二逼平衡树 [树状数组套可持久化主席树]

    ( ext{Description})

    ( ext{Sample})

    ( ext{Input})

    8 10
    93193828 87467295 7194563 77236060 94622726 47450113 70878734 52950301 
    2 6 8 2
    5 4 6 89104605
    3 7 62289938
    3 4 94396652
    4 7 7 36968499
    4 8 8 42956931
    4 1 2 30670581
    5 7 7 7587866
    1 7 7 74144921
    1 3 3 53352412
    

    ( ext{Output})

    52950301
    94622726
    -2147483647
    -2147483647
    -2147483647
    62289938
    2
    2
    

    ( ext{Solution})

    主要是有修改操作,普通的持久化主席树因为类似一个前缀和,只能 (mathcal O(nlog n)) 修改一次。类似优化前缀和,我们可以用树状数组优化主席树。

    注意一下:树状数组优化实质上是优化下标的选取。

    所以可持久化主席树是以 (l-1,r) 下标建的树做差,树状数组套可持久化主席树就是以 ((l-1,l-1-lowbit(l-1),...),(r,r-lowbit(r)...)) 下标建的树做差。

    我们预处理出上面那一坨下标对应的树的根,在各种函数中相减就行了。

    总时间复杂度 (mathcal O(n log^2 n))

    ( ext{Code})

    #include <cstdio>
    
    #define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
    #define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
    #define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define print(x,y) write(x),putchar(y)
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
    template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
    template <class T> inline T fab(const T x) {return x>0?x:-x;}
    template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
    template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
    template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}
    
    #include <algorithm>
    using namespace std;
    
    const int inf=2147483647,maxn=5e4+5;
    
    int n,m,a[maxn],b[maxn<<1],tot,sz,son[maxn*16*16][2],siz[maxn*16*16],rt[maxn],x[maxn],y[maxn],l[maxn],r[maxn];
    
    int lowbit(int x) {return x&-x;}
    
    int modify(int pre,int l,int r,int p,int k) {
    	int x=++sz;
    	son[x][0]=son[pre][0],son[x][1]=son[pre][1],siz[x]=siz[pre]+k;
    	if(l==r) return x;
    	int mid=l+r>>1;
    	if(p<=mid) son[x][0]=modify(son[pre][0],l,mid,p,k);
    	else son[x][1]=modify(son[pre][1],mid+1,r,p,k);
    	return x;
    }
    
    void add(int i,int k) {
    	int x=i;
    	while(x<=n) rt[x]=modify(rt[x],1,tot,a[i],k),x+=lowbit(x);//注意这里是从自己开始更改而不是从上一个更改,毕竟已经不是前缀和了
    }
    
    void init(int i) {
    	x[0]=y[0]=0;
    	for(int p=l[i]-1;p;p-=lowbit(p)) x[++x[0]]=rt[p];
    	for(int p=r[i];p;p-=lowbit(p)) y[++y[0]]=rt[p];
    }
    
    int rank(int l,int r,int k) {//这个函数实际上是查 k 前面有多少个数
    	if(l==r) return 0;
    	int mid=l+r>>1;
    	if(k<=mid) {
    		rep(i,1,x[0]) x[i]=son[x[i]][0];
    		rep(i,1,y[0]) y[i]=son[y[i]][0];
    		return rank(l,mid,k);
    	}
    	int ret=0;
    	rep(i,1,x[0]) ret-=siz[son[x[i]][0]],x[i]=son[x[i]][1];
    	rep(i,1,y[0]) ret+=siz[son[y[i]][0]],y[i]=son[y[i]][1];
    	return rank(mid+1,r,k)+ret;
    }
    
    int kth(int l,int r,int k) {
    	if(l==r) return b[l];
    	int mid=l+r>>1,ret=0;
    	rep(i,1,x[0]) ret-=siz[son[x[i]][0]];
    	rep(i,1,y[0]) ret+=siz[son[y[i]][0]];
    	if(ret>=k) {
    		rep(i,1,x[0]) x[i]=son[x[i]][0];
    		rep(i,1,y[0]) y[i]=son[y[i]][0];
    		return kth(l,mid,k);
    	}
    	rep(i,1,x[0]) x[i]=son[x[i]][1];
    	rep(i,1,y[0]) y[i]=son[y[i]][1];
    	return kth(mid+1,r,k-ret);
    }
    
    int main() {
    	int op[maxn],k[maxn];
    	n=read(9),m=read(9);
    	rep(i,1,n) a[i]=b[i]=read(9);
    	tot=n;
    	rep(i,1,m) {
    		op[i]=read(9),l[i]=read(9),r[i]=read(9);
    		if(op[i]^3) k[i]=read(9);
    		else b[++tot]=r[i];
    		if((op[i]^2)&&(op[i]^3)) b[++tot]=k[i];
    	}
    	sort(b+1,b+tot+1);
    	tot=unique(b+1,b+tot+1)-b-1;
    	rep(i,1,n) {
    		a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
    		add(i,1);
    	}
    	rep(i,1,m) {
    		if(op[i]^3) init(i);
    		if((op[i]^2)&&(op[i]^3)) k[i]=lower_bound(b+1,b+tot+1,k[i])-b;
    		if(op[i]==1) print(rank(1,tot,k[i])+1,'
    ');
    		if(op[i]==2) print(kth(1,tot,k[i]),'
    ');
    		if(op[i]==3) add(l[i],-1),a[l[i]]=lower_bound(b+1,b+tot+1,r[i])-b,add(l[i],1);
    		if(op[i]==4) {
    			int t=rank(1,tot,k[i]);
    			if(!t) print(-inf,'
    ');
    			else init(i),print(kth(1,tot,t),'
    ');
    		}
    		if(op[i]==5) {
    			int t=rank(1,tot,k[i]+1);
    			if(t>=r[i]-l[i]+1) print(inf,'
    ');
    			else init(i),print(kth(1,tot,t+1),'
    ');
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    JSP--------------------图书管理器
    Vue-router的基本使用(创建--动态跳转)
    JSP邮箱小案例(完成全部功能)
    Vue CLI3脚手架的使用
    Vue小案例测试-------------------实现购物车小模块
    JSP第六次作业提交~~~~~~~~~~~~~~~~~~~~~
    JSP项目第二阶段(使用数据库存储与注册)
    jsp第三次作业-------------------------------
    2021/4/19作业
    4.12作业
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/13656147.html
Copyright © 2011-2022 走看看