• BZOJ.1901.Dynamic Rankings(线段树套平衡树 Splay)


    题目链接or Here

    题意:n个数,有两个操作:1.修改某个数为v;2.询问一段区间第k小的数

    如果没有修改,则可以用线段树,每个节点P[a,b]存储大小为b-a+1的数组,代表其中的数
    同时,这个数组还是要排好序的
    直接找答案很不方便,于是考虑对数组二分答案,求比它小的数的个数
    关于构造过程,更新完子节点后,子节点维护的数组就是有序的了,可以通过归并得到父节点的有序数组
    这样空间 (O(nlogn)),每次查询时间 (O(log^2n))

    修改同时有序,二叉排序树是好选择
    线段树每个节点维护一棵平衡树,查询时在平衡树中查询;
    修改一个点就将它从平衡树中删掉,更改后再插入(所有包含这个点的区间都要执行)
    空间复杂度为 (O(dep*n)),dep为线段树的深度,大约就是 (O(nlogn))
    时间 (O(nlog^3n))

    树状数组+主席树见这.
    整体二分见这.

    //41644 kb  2404 ms
    #include<cstdio>
    #include<cctype>
    #define gc() getchar()
    //#define gc() (SS==TT &&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    const int N=1e5+5,M=15*N,MAXIN=5e6;
    
    int n,q,tot,A[N],root[N],size,fa[M],son[M][2],sz[M],cnt[M],t[M];
    char IN[MAXIN],*SS=IN,*TT=IN;
    
    inline int read()
    {
    	int now=0,f=1;register char c=gc();
    	for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now*f;
    }
    
    inline void Update(int rt)
    {
    	sz[rt]=sz[son[rt][0]]+sz[son[rt][1]]+cnt[rt];
    }
    void Rotate(int x,int &k)
    {
    	int a=fa[x],b=fa[a],l=son[a][1]==x,r=l^1;
    	if(a==k) k=x;
    	else son[b][son[b][1]==a]=x;
    	fa[x]=b, fa[a]=x, fa[son[x][r]]=a,
    	son[a][l]=son[x][r], son[x][r]=a;
    	Update(a), Update(x);
    }
    void Splay(int x,int &k)
    {
    	while(x!=k)
    	{
    		int a=fa[x],b=fa[a];
    		if(a!=k)
    		{
    			if((son[a][0]==x)^(son[b][0]==a)) Rotate(x,k);
    			else Rotate(a,k);
    		}
    		Rotate(x,k);
    	}
    }
    void Get_Rank(int v,int x)
    {
    	if(!root[x]) return;//!
    	int k=root[x];
    	while(t[k]!=v && son[k][v>t[k]]) k=son[k][v>t[k]];
    	Splay(k,root[x]);
    }
    void Insert(int v,int x)
    {
    	int f=0,k=root[x];
    	while(k && v!=t[k]) f=k,k=son[k][v>t[k]];
    	if(k) ++cnt[k];
    	else
    	{
    		k=++size, cnt[k]=sz[k]=1, t[k]=v, fa[k]=f;
    		if(f) son[f][v>t[f]]=k;
    	}
    	Splay(k,root[x]);
    }
    void Delete(int v,int x)
    {
    	Get_Rank(v,x);
    	int k=root[x];
    	if(cnt[k]>1) {--cnt[k],--sz[k]; return;}
    	else if(!son[k][0]||!son[k][1]) root[x]=son[k][0]|son[k][1];
    	else
    	{
    		int p=son[k][0];
    		k=son[k][1], root[x]=k;//!
    		while(son[k][0]) k=son[k][0];
    		sz[k]+=sz[p], fa[p]=k, son[k][0]=p;
    		Splay(k,root[x]);
    	}
    	fa[root[x]]=0;//!
    }
    void Build(int l,int r,int rt,int pos)
    {
    	Insert(A[pos],rt);
    	if(l==r) return;
    	int m=l+r>>1;
    	if(pos<=m) Build(l,m,rt<<1,pos);
    	else Build(m+1,r,rt<<1|1,pos);
    }
    void Modify(int l,int r,int rt,int pos,int v)
    {
    //	printf("Modify:%d~%d rt:%d pos:%d v:%d
    ",l,r,rt,pos,v);
    	Delete(A[pos],rt), Insert(v,rt);
    	if(l>=r) return;
    	int m=l+r>>1;
    	if(pos<=m) Modify(l,m,rt<<1,pos,v);
    	else Modify(m+1,r,rt<<1|1,pos,v);
    }
    void Calc(int v,int k)
    {
    	while(k)
    	{
    //		printf("k:%d v:%d tot:%d
    ",k,v,tot);
    		if(v==t[k]) {tot+=sz[son[k][0]]; return;}
    		if(v>t[k]) tot+=sz[son[k][0]]+cnt[k],k=son[k][1];
    		else k=son[k][0];
    	}
    }
    void Query(int l,int r,int rt,int L,int R,int v)
    {
    //	printf("Query:%d~%d rt:%d L~R:%d~%d v:%d
    ",l,r,rt,L,R,v);
    	if(L<=l && r<=R) {Calc(v,root[rt]); return;}
    	int m=l+r>>1;
    	if(L<=m) Query(l,m,rt<<1,L,R,v);
    	if(m<R) Query(m+1,r,rt<<1|1,L,R,v);
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("1901.in","r",stdin);
    //	freopen("1901.out","w",stdout);
    #endif
    
    	n=read(),q=read();
    	for(int i=1;i<=n;++i) A[i]=read(),Build(1,n,1,i);
    	char s[5];
    	int i,j,k;
    	while(q--)
    	{
    		scanf("%s",s),i=read(),j=read();
    		if(s[0]=='C') Modify(1,n,1,i,j),A[i]=j;
    		else
    		{
    			k=read();
    			int l=0,r=1e9,m,ans=0;
    			while(l<=r)
    			{
    				m=l+r>>1;
    				tot=0, Query(1,n,1,i,j,m);
    //				printf("%d~%d %d
    ",l,r,tot);
    				if(tot>=k) r=m-1;
    				else l=m+1,ans=m;
    			}
    			printf("%d
    ",ans);
    		}
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    git shell自动打tag
    git 获取最新的匹配到的tag
    centOS debian ubuntu 一键安装 docker 教程
    git将当前分支的修改推到其他分支
    MusicPlayer2
    Ventoy 多合一启动盘制作工具神器
    electron-builder 下载 electron过慢或报错的解决办法
    解决npm install 报错“npm WARN pug-loader@2.4.0 requires a peer of pug@^2.0.0 but none is installed. You must install peer dependencies yourself.“
    全能笔记软件 Notion 的“中国版" wolai
    Your branch is behind 'origin/master' by N commits, and can be fast-forwarded 解决方法
  • 原文地址:https://www.cnblogs.com/SovietPower/p/8434999.html
Copyright © 2020-2023  润新知