poj 2761 Feed the dogs 平衡树,线段树,树状数组

分析:这题就是求区间第k小数,但是这题和poj2104的区别就是,2104的区间是可以完全包含的,就是说某个点进出区间不止一次,所以平衡树和线段树是超时的,只能用划分树或者归并树,这题是可以用平衡树解的。先把区间从左到右排序,然后依次插入平衡树,线段树,然后利用树的性质在log n 内找到第k小。这题也可以用树状数组解,但是需要二分第k小,我一直觉得二分不是最好的做法,考虑能不能在log n内用树状数组找到第k小,一直做不到,所以这题没用树状数组写。

再说一下,平衡树中,treap最好写,sbt据说最快,而且附加域是有用的,是树的节点个数size,而伸展树很灵活可以快速合并分裂翻转,可以实现其他平衡树做不到的。

个人认为,必须要学会伸展树,然后SBT和treap一定要会一种。我学的是SBT。

然后,线段树需要先对数据二分+离散化,因为可能出现很大的值,很浪费内存。

因为要对区间排序,所以要保存区间的顺序下标,最后输出答案有两种方法,一种是获得解后重新按照区间出现顺序排序,第二种是直接ans[interval[i].index]=interval[i].k;

下面是三种不同的解法,线段树,SBT,伸展树。

最后,因为这一题开始只用了线段树写的,后面两种写法是后来学平衡树的时候写的,所以在判断区间重叠的时候不一样。后面多考虑了区间完全重叠的情况,这个数据是没有的,只是为了对拍数据用的。可以删掉。

线段树:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100005
#define M 50005
int n,m;
int pretty[N];
int dog[N];
struct inter{
    int l,r,k;
    int ans;
    int index;
}interval[M];
struct tree{
    int l,r,p;
}tree[N<<2];
int binary(int key)
{
    int l=1,r=n;
    while(l<=r){
        int mid=(l+r)>>1;
        if(pretty[mid]==key) return mid;
        else if(key<pretty[mid]) r=mid-1;
        else l=mid+1;
    }
}

void build(int rt,int l,int r)
{
    tree[rt].l=l;tree[rt].r=r;
    if(l<r){
        int mid=(l+r)>>1;
        build(rt<<1,l,mid);
        build(rt<<1|1,mid+1,r);
    }
}
void insert(int rt,int i,int d)
{
    tree[rt].p+=d;
    if(tree[rt].l!=tree[rt].r){
        int mid=(tree[rt].l+tree[rt].r)>>1;
        if(mid>=i) insert(rt<<1,i,d);
        else insert(rt<<1|1,i,d);
    }
}
inline bool cmp(const inter &a, const inter &b)
{
    return a.l<b.l||(a.l==b.l&&a.r<b.r);
}
inline bool operator<(const inter &a, const inter &b)
{
    return a.index<b.index;
}
int query(int rt,int k)
{
    if(tree[rt].l==tree[rt].r) return pretty[tree[rt].l];
    if(tree[rt<<1].p>=k) return query(rt<<1,k);
    else return query(rt<<1|1,k-tree[rt<<1].p);
}
int main()
{
    memset(tree,0,sizeof(tree));
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++){
        scanf("%d",pretty+i);
        dog[i]=pretty[i];
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&interval[i].l,&interval[i].r,&interval[i].k);
        interval[i].index=i;
    }
    sort(pretty+1,pretty+n+1);
    sort(interval+1,interval+m+1,cmp);
    for(int i=1;i<=n;i++)
        dog[i]=binary(dog[i]);
    build(1,1,n);
    for(int i=interval[1].l;i<=interval[1].r;i++)
        insert(1,dog[i],1);
    interval[1].ans=query(1,interval[1].k);
    for(int i=2;i<=m;i++){
        if(interval[i].l<=interval[i-1].r){
            for(int j=interval[i-1].l;j<interval[i].l;j++)
                insert(1,dog[j],-1);
            for(int j=interval[i-1].r+1;j<=interval[i].r;j++)
                insert(1,dog[j],1);
        }else{
            for(int j=interval[i-1].l;j<=interval[i-1].r;j++)
                insert(1,dog[j],-1);
            for(int j=interval[i].l;j<=interval[i].r;j++)
                insert(1,dog[j],1);
        }
        interval[i].ans=query(1,interval[i].k);
    }
    sort(interval+1,interval+m+1);
    for(int i=1;i<=m;i++)
        printf("%d\n",interval[i].ans);
    return 0;
}

SBT:

#include<cstdio>
#include<algorithm>
const int maxn = 100009;
const int maxm = 50009;
struct cnode{
	cnode *lchild,*rchild;
	int s,key;
}node[maxn];
int sz=1;
inline cnode *newnode(cnode*l,cnode*r,int s,int key){
	node[sz].lchild=l;
	node[sz].rchild=r;
	node[sz].s=s;
	node[sz].key=key;
	return node+sz++;
}
struct SBT{
	cnode *root;
	cnode *null;
	SBT(){
		root=null=node;
		node[0].s=0;node[0].key=-1;
		null->lchild=null->rchild=null;
	}
	~SBT(){
		root=null=NULL;
	}
	void rotate_r(cnode*&t){
		cnode *temp=t->lchild;
		t->lchild=temp->rchild;
		temp->rchild=t;
		temp->s=t->s;
		t->s=t->lchild->s+t->rchild->s+1;
		t=temp;
	}
	void rotate_l(cnode*&t){
		cnode *temp=t->rchild;
		t->rchild=temp->lchild;
		temp->lchild=t;
		temp->s=t->s;
		t->s=t->lchild->s+t->rchild->s+1;
		t=temp;
	}
	void maintain(cnode*&t,bool type){
		if(t==null)return;
		if(!type){
			if(t->lchild->lchild->s > t->rchild->s){
				rotate_r(t);
			}else if(t->lchild->rchild->s > t->rchild->s){
				rotate_l(t->lchild);
				rotate_r(t);
			}else return;
		}else{
			if(t->rchild->rchild->s > t->lchild->s){
				rotate_l(t);
			}else if(t->rchild->lchild->s > t->lchild->s){
				rotate_r(t->rchild);
				rotate_l(t);
			}else return;
		}
		maintain(t->lchild,false); maintain(t->rchild,true);
		maintain(t,false);maintain(t,true);
	}
	void insert(cnode*&t,int key){

		if(t==null){
			t=newnode(null,null,1,key);
			return;
		}
		t->s++;
		if(key < t->key) insert(t->lchild,key);
		else insert(t->rchild,key);
		maintain(t,key>=root->key);
	}

	void erase(cnode*&t,int key){
		if(t==null) return;
		t->s--;
		if(t->key==key){
			if(t->lchild!=null&&t->rchild==null){
				t=t->lchild;
			}else if( t->lchild==null && t->rchild==null){
				t=null;
			}else{
				cnode*temp=t->rchild;
				while(temp->lchild!=null){temp=temp->lchild;}
				t->key=temp->key;erase(t->rchild,temp->key);
			}
		}else if(key<t->key){
			erase(t->lchild,key);
		}else{
			erase(t->rchild,key);
		}
	}
	int kth(int k){
	//	printf("s: %d",root->s);
	//	travel();
		cnode *t=root;
		while(1){
			if(t->lchild->s==k-1)return t->key;
			else if(t->lchild->s > k-1){
				t=t->lchild;
			}else{
				k-=1+t->lchild->s;
				t=t->rchild;
			}
		}
	}
	void erase(int key){
		erase(root,key);
	}
	void insert(int key){
		insert(root,key);
	}
	void travel(){
		travel(root);
	}
	void travel(cnode *t){
		if(t!=null){
			travel(t->lchild);
			printf("%d %d\n",t->s,t->key);
			travel(t->rchild);
		}
	}
};
SBT tree;


struct A{
	int l,r,k,i;
}interval[maxn];
int a[maxn];
bool cmp2(const A&a,const A&b){
	return a.l<b.l||a.l==b.l&&a.r<b.r;
}
bool cmp(const A&a,const A&b){
	return a.i<b.i;
}
int main(){
	int m,n;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",a+i);
	}
	for(int i=0;i<m;i++){scanf("%d %d %d",&interval[i].l,&interval[i].r,&interval[i].k);interval[i].i=i;}
	std::sort(interval,interval+m,cmp2);
	int r=interval[0].r,l=interval[0].l;
	for(int i=l;i<=r;i++) tree.insert(a[i]);
	interval[0].k=tree.kth(interval[0].k);
	for(int i=1;i<m;i++){
		int R=interval[i].r,L=interval[i].l;
		if(L>r){
			while(l<=r){
				tree.erase(a[l++]);
			}
			l=L;r=R;
			while(L<=R){
				tree.insert(a[L++]);
			}
		}else if(R>r){
			while(l<L){
				tree.erase(a[l++]);
			}
			while(++r<=R){
				tree.insert(a[r]);
			}
			--r;
		}
		else{
			while(l<L){
				tree.erase(a[l++]);
			}
			while(r>R){
				tree.erase(a[r--]);
			}
		}
		interval[i].k=tree.kth(interval[i].k);
	}
	std::sort(interval,interval+m,cmp);
	for(int i=0;i<m;i++)
		printf("%d\n",interval[i].k);
	return 0;
}
Splay:

#include<cstdio>
#include<algorithm>
const int INF = (unsigned(~0))>>1;
const int maxm = 50009;
const int maxn = 100009;
struct splaytree{
    int sz;
    struct node{
        int s,v;
        node *parent;
        node *child[2];
    };
    node pool[maxn];
    node* null;
    node* root;
    node nil;
    splaytree(){
        root=null=&nil;
        nil.parent=nil.child[0]=nil.child[1]=null;
        sz=nil.v=nil.s=0;
        insert(-INF);
        insert(INF);
    }
    node* newnode(node*p,int key){
        pool[sz].parent=p;
        pool[sz].child[0]=pool[sz].child[1]=null;
        pool[sz].s=1;
        pool[sz].v=key;
        return pool+sz++;
    }
    void update(node* x){
        if(x != null){
            x->s = x->child[0]->s + x->child[1]->s + 1;
        }
    }
    void insert(int key){

        if(root==null){
            root=newnode(null,key);
        }else{
            node *t=root;
            while(true){
                int d=t->v < key;
                t->s++;
                if(t->child[d]==null){
                    t->child[d] = newnode(t,key);
                    splay(t->child[d],null);
                    return;
                }else{
                    t=t->child[d];
                }
            }
        }
    }
    void remove(int value){

        int k=find(value);
        findkth(k-1,null);
        findkth(k+1,root);
        root->s--;
        root->child[1]->s--;
        root->child[1]->child[0]=null;
    }
    void rotate(node *x,int dr){
        node *p = x->parent;
        x->child[dr]->parent=p;
        p->child[1^dr] = x->child[dr];
        x->parent=p->parent;
        x->child[dr]=p;
        if(p->parent->child[0]==p){
            p->parent->child[0]=x;
        }else if(p->parent->child[1]==p){
            p->parent->child[1]=x;
        }else   root=x;
        p->parent=x;
        update(p);
        update(x);
    }
    void splay(node *x, node *y){
        while(x->parent != y){
            if(x->parent->parent==y){
                if(x->parent->child[0]==x)rotate(x,1);
                else rotate(x,0);
            }else if(x->parent->parent->child[0] == x->parent){
                if(x->parent->child[0]==x){
                    rotate(x->parent,1);
                    rotate(x,1);
                }else{
                    rotate(x,0);
                    rotate(x,1);
                }
            }else{
                if(x->parent->child[1]==x){
                    rotate(x->parent,0);
                    rotate(x,0);
                }else{
                    rotate(x,1);
                    rotate(x,0);
                }
            }
        }
    }
    int find(int key){
        node *t=root;
        int sum=0;
        while(true){
            if(t->v == key){
                return sum + t->child[0]->s + 1;
            }else if(t->v > key){
                t = t->child[0];
            }else{
                sum += t->child[0]->s + 1;
                t = t->child[1];
            }
        }
    }
    int getkth(int k){

        findkth(k+1,null);

        return root->v;
    }
    void findkth(int k,node *y){
        node *x = root;
        while(k != x->child[0]->s + 1){
            if(k < x->child[0]->s + 1 ){
                x = x->child[0];
            }else{
                k -= x->child[0]->s + 1;
                x = x->child[1];
            }
        }

        splay(x,y);
    }

};
splaytree tree;
struct A{
	int l,r,i,k;
}interval[maxn];
int a[maxn];
int ans[maxm];
bool operator<(const A&a,const A&b){
	return a.l<b.l||a.l==b.l&&a.r<b.r;
}
int main(){
    int m,n;
	scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",a+i);
        }

        for(int i=0;i<m;i++){scanf("%d %d %d",&interval[i].l,&interval[i].r,&interval[i].k);interval[i].i=i;}
        std::sort(interval,interval+m);
        int r=interval[0].r,l=interval[0].l;
        for(int i=l;i<=r;i++) tree.insert(a[i]);
        ans[interval[0].i]=tree.getkth(interval[0].k);
        for(int i=1;i<m;i++){
            int R=interval[i].r,L=interval[i].l;
            if(L>r){
                while(l<=r){
                    tree.remove(a[l++]);
                }
                l=L;r=R;
                while(L<=R){
                    tree.insert(a[L++]);
                }
            }else if(R>r){
                while(l<L){
                    tree.remove(a[l++]);
                }
                while(++r<=R){
                    tree.insert(a[r]);
                }
                --r;
            }
            else{
                while(l<L){
                    tree.remove(a[l++]);
                }
                while(r>R){
                    tree.remove(a[r--]);
                }
            }
            ans[interval[i].i]=tree.getkth(interval[i].k);
        }
        for(int i=0;i<m;i++)
            printf("%d\n",ans[i]);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值