zoukankan      html  css  js  c++  java
  • 【模板】二逼平衡树(树套树)

    IV.【模板】二逼平衡树(树套树)

    树状数组套权值线段树最好了……\(n\log^2n\)的复杂度可比\(n\log^3n\)的什么线段树套平衡树要强一百万倍!其实是我不会写

    分析一下操作:

    1. 二分出来最大的\(<k\)的数后直接权值线段树上查询前缀和。

    2. 就是II.Dynamic Rankings

    3. 直接修改。

    4. 权值线段树上二分前驱。

    5. 权值线段树上二分后继。

    操作全都是\(O(\log^2n)\)的。

    敲出来,一遍\(90\%\),TLE一个点,祭出快读,AC。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define mid ((l+r)>>1)
    int n,m,cnt,bin[1001000],tp,root[50100],lim,val[50100];
    struct node{
    	int lson,rson,sum;
    }seg[5010000];
    vector<int>v;
    inline void newnode(int &x){
    	if(!tp)x=++cnt;
    	else x=bin[tp--];
    }
    inline void segmod(int &x,int l,int r,int P,int val){
    	if(l>P||r<P)return;
    	if(!x)newnode(x);
    	seg[x].sum+=val;
    	if(l!=r)segmod(seg[x].lson,l,mid,P,val),segmod(seg[x].rson,mid+1,r,P,val);
    	if(!seg[x].sum)bin[++tp]=x,x=0;
    }
    inline void finmod(int x,int P,int k){
    	while(x<=n)segmod(root[x],1,lim,P,k),x+=x&-x;
    }
    inline void modify(int x,int y){
    	y=lower_bound(v.begin(),v.end(),y)-v.begin()+1;
    	finmod(x,val[x],-1);
    	finmod(x,val[x]=y,1);
    }
    inline int segkth(vector<int>&x,vector<int>&y,int l,int r,int k){
    	int lsum=0;
    	if(l==r)return v[l-1];
    	for(auto i:x)lsum+=seg[seg[i].lson].sum;
    	for(auto i:y)lsum-=seg[seg[i].lson].sum;
    	if(lsum>=k){
    		for(auto &i:x)i=seg[i].lson;
    		for(auto &i:y)i=seg[i].lson;
    		return segkth(x,y,l,mid,k);
    	}else{
    		for(auto &i:x)i=seg[i].rson;
    		for(auto &i:y)i=seg[i].rson;
    		return segkth(x,y,mid+1,r,k-lsum);		
    	}
    }
    inline int finkth(int l,int r,int k){
    	vector<int>x,y;
    	l--;
    	while(l)y.push_back(root[l]),l-=l&-l;
    	while(r)x.push_back(root[r]),r-=r&-r;
    	return segkth(x,y,1,lim,k);
    }
    inline int segrak(int x,int l,int r,int L,int R){
    	if(!x||l>R||r<L)return 0;
    	if(L<=l&&r<=R)return seg[x].sum;
    	return segrak(seg[x].lson,l,mid,L,R)+segrak(seg[x].rson,mid+1,r,L,R);
    }
    inline int finrak(int x,int y){
    	int sum=0;
    	while(x)sum+=segrak(root[x],1,lim,1,y),x-=x&-x;
    	return sum;
    }
    inline int rak(int l,int r,int x){
    	x=lower_bound(v.begin(),v.end(),x)-v.begin();
    	return finrak(r,x)-finrak(l-1,x)+1;
    }
    inline int segpre(vector<int>&x,vector<int>&y,int l,int r,int k){
    	int sum=0;
    	for(auto i:x)sum+=seg[i].sum;
    	for(auto i:y)sum-=seg[i].sum; 
    	if(!sum||l>k)return *v.begin();
    	if(l==r)return v[l-1];
    	vector<int>p,q;
    	p.clear(),q.clear();
    	for(auto i:x)p.push_back(seg[i].rson);
    	for(auto i:y)q.push_back(seg[i].rson);
    	int tmp=segpre(p,q,mid+1,r,k);
    	if(tmp!=*v.begin())return tmp;
    	p.clear(),q.clear();
    	for(auto i:x)p.push_back(seg[i].lson);
    	for(auto i:y)q.push_back(seg[i].lson);
    	return segpre(p,q,l,mid,k);
    }
    inline int finpre(int l,int r,int k){
    	k=lower_bound(v.begin(),v.end(),k)-v.begin();
    	vector<int>x,y;
    	l--;
    	while(l)y.push_back(root[l]),l-=l&-l;
    	while(r)x.push_back(root[r]),r-=r&-r;
    	return segpre(x,y,1,lim,k);
    }
    inline int segsuf(vector<int>&x,vector<int>&y,int l,int r,int k){
    	int sum=0;
    	for(auto i:x)sum+=seg[i].sum;
    	for(auto i:y)sum-=seg[i].sum;
    	if(!sum||r<k)return *v.rbegin();
    	if(l==r)return v[l-1];
    	vector<int>p,q;
    	p.clear(),q.clear();
    	for(auto i:x)p.push_back(seg[i].lson);
    	for(auto i:y)q.push_back(seg[i].lson);
    	int tmp=segsuf(p,q,l,mid,k);
    	if(tmp!=*v.rbegin())return tmp;
    	p.clear(),q.clear();
    	for(auto i:x)p.push_back(seg[i].rson);
    	for(auto i:y)q.push_back(seg[i].rson);
    	return segsuf(p,q,mid+1,r,k);
    }
    inline int finsuf(int l,int r,int k){
    	k=upper_bound(v.begin(),v.end(),k)-v.begin()+1;
    	vector<int>x,y;
    	l--;
    	while(l)y.push_back(root[l]),l-=l&-l;
    	while(r)x.push_back(root[r]),r-=r&-r;
    	return segsuf(x,y,1,lim,k);
    }
    struct opt{
    	int op,t1,t2,t3;
    }q[50100];
    inline void read(int &x){
    	x=0;
    	char c=getchar();
    	while(c>'9'||c<'0')c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    }
    inline void print(int x){
    	if(x<0)putchar('-'),print(-x);
    	else if(x<=9)putchar('0'+x);
    	else print(x/10),putchar('0'+x%10);
    }
    int main(){
    	read(n),read(m),v.push_back(-2147483647),v.push_back(2147483647);
    	for(int i=1;i<=n;i++)read(val[i]),v.push_back(val[i]);
    	for(int i=1;i<=m;i++){
    		read(q[i].op),read(q[i].t1),read(q[i].t2);
    		if(q[i].op==3)v.push_back(q[i].t2);
    		else read(q[i].t3);
    	}
    	sort(v.begin(),v.end()),v.resize(lim=(unique(v.begin(),v.end())-v.begin()));
    //	for(auto x:v)printf("%d ",x);puts("");
    	for(int i=1;i<=n;i++)finmod(i,val[i]=lower_bound(v.begin(),v.end(),val[i])-v.begin()+1,1);
    //	puts("IN");
    	for(int i=1;i<=m;i++){
    		if(q[i].op==1)print(rak(q[i].t1,q[i].t2,q[i].t3)),putchar('\n');
    		if(q[i].op==2)print(finkth(q[i].t1,q[i].t2,q[i].t3)),putchar('\n');
    		if(q[i].op==3)modify(q[i].t1,q[i].t2);
    		if(q[i].op==4)print(finpre(q[i].t1,q[i].t2,q[i].t3)),putchar('\n');
    		if(q[i].op==5)print(finsuf(q[i].t1,q[i].t2,q[i].t3)),putchar('\n');
    	}
    	return 0;
    } 
    

  • 相关阅读:
    无法设置 / 添加网络打印机?报错 无法保持设置?
    tp剩余未验证内容-5
    再谈 iptables 防火墙的 指令配置
    tp剩余未验证内容-4
    tp剩余未验证内容-3
    CentOS7.4安装配置mysql8 TAR免安装版
    CentOS7中systemctl的使用与CentOS6中service的区别
    CentOS下如何查看并杀死僵尸进程
    CentOS SVN服务器管理多项目
    swoole+Redis实现实时数据推送
  • 原文地址:https://www.cnblogs.com/Troverld/p/14611082.html
Copyright © 2011-2022 走看看