zoukankan      html  css  js  c++  java
  • treap树【一本通题目】

    Treap树:平衡树的一种

    数和堆的集合,每个节点有值,也有优先级,那么这棵树的形态就被确定了,和插入顺序无关了(有赖于优先级

    避免退化成链:在生成节点时,随机生成优先级,然后插入时动态调整

    删除:如果有两个子节点,找到优先级大的,把x向反方向旋转,也就是把x向树的下层调整,直到旋转到叶子节点

    !很多题目涉及名次树

    常用操作:

    struct node,旋转rotate,插入insert(),查找第k大的数kth(),查询某个数find()【名次树】

    旋转zig(右旋)/tag(左旋)操作

    splay树和treap树https://www.cnblogs.com/shirlybaby/p/12393268.html 

    【一本通】

    1565:【例 1】营业额统计

     有很多种方法

    第一种方法;直接用set做

    但是注意一点(怎么看出来的...)就是有一个点差一个输入,其他直接lowerboundupperbound就可以了

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<stack>
    #include<cstdio>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    using namespace std;
    const int maxn=1010;
    const int INF=0x3fffffff;
    typedef long long LL;
    typedef unsigned long long ull;
    //可以用set过
    //有一个点少了一个输入的样子 
    set<int> st;
    int n,x; 
    int main(){
    	scanf("%d",&n);
    	int ans;
    	scanf("%d",&x);
    	ans=x;
    	st.insert(INF);
    	st.insert(-INF);
    	//插入正无穷和负无穷,防止迭代器访问到一些奇奇怪怪的内存
    	st.insert(x);  //第一个单独考虑
    	for(int i=1;i<n-1;i++){
    		scanf("%d",&x);
    		int l=*(--st.lower_bound(x)); //大于等于(第一个)所以减一就是小于 
    		int r=*st.lower_bound(x);  //大于 
    		if(x-l>r-x) ans+=r-x;
    		else ans+=x-l;
    		st.insert(x);
    	}
    	if(scanf("%d",&x)==1){
    		int l=*(--st.lower_bound(x));
    		int r=*st.lower_bound(x);
    		if(x-l>r-x) ans+=r-x;
    		else ans+=x-l;
    		st.insert(x);
    	}
    	else{
    		x=0;
    		int l=*(--st.lower_bound(x));
    		int r=*st.lower_bound(x);
    		if(x-l>r-x) ans+=r-x;
    		else ans+=x-l;
    		st.insert(x);
    	}
    	printf("%d
    ",ans); 
    return 0;
    }
    

    第二种方法:离线+排序

    用链表做,不容易想到

    首先排序,然后插入链表
    r[i]表示原来的a[i]在链表中的位置
    倒序处理,把r[i]的ans贡献算出来,然后删除r[i]指向的位置
    为什么这样可行呢?
    因为是离线+排序,所以每个元素之间的关系是已知的
    倒序处理时,对于每个a[i],链表就是前i个元素组成的【学会呀!】

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<stack>
    #include<cstdio>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    using namespace std;
    const int maxn=1010;
    const int INF=0x3fffffff;
    typedef long long LL;
    /*
    首先排序,然后插入链表
    r[i]表示原来的a[i]在链表中的位置
    倒序处理,把r[i]的ans贡献算出来,然后删除r[i]指向的位置
    为什么这样可行呢?
    因为是离线+排序,所以每个元素之间的关系是已知的
    倒序处理时,对于每个a[i],链表就是前i个元素组成的
    */
    typedef unsigned long long ull;
    struct node{
    	int pre,next;
    }b[32768];
    struct data{
    	int d;
    	int rak;
    }a[32768];
    int r[32768];
    int n,ans;
    bool cmp(data x,data y){
    	if(x.d!=y.d) return x.d<y.d;
    	else return x.rak<y.rak;
    }
    void del(int x){
    	b[b[x].next].pre=b[x].pre;
    	b[b[x].pre].next=b[x].next;
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i].d);
    		a[i].rak=i;
    	}
    	sort(a+1,a+1+n,cmp);
    	for(int i=1;i<=n;i++){
    		r[a[i].rak]=i; //r[]表示的是原来的下标在现在的排名 
    		if(i!=n) b[i].next=i+1;
    		b[i].pre=i-1;
    	}
    	int j,k;
    	for(int i=n;i;i--){
    		j=0;k=0;
    		int x=r[i];  //原来的输入里面第i个现在的排名 
    		if(b[x].pre) j=abs(a[b[x].pre].d-a[x].d);
    		else j=INF;
    		if(b[x].next) k=abs(a[b[x].next].d-a[x].d);
    		else k=INF;
    		if(i!=1) ans+=min(j,k);
    		else ans+=a[x].d;
    		del(x);
    		r[i]=0; 
    	}
    	printf("%d
    ",ans);
    	
    return 0;
    }
    

    第三种方法:splay树

    提根操作!左右旋操作,这个不好写也不好记

    注意如果发现已经有这个数的话,就不要再计算前驱和后继了,肯定加的是0

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<stack>
    #include<cstdio>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    using namespace std;
    const int maxn=100100;
    const int INF=0x3fffffff;
    typedef long long LL;
    typedef unsigned long long ull;
    //第三种做法   平衡树 splay
    int root,tot;
    struct tree{
    	int key;
    	int son[2];  //son[0]左儿子,son[1]右儿子
    	int fa;   
    }T[maxn]; 
    void newnode(int &r,int w,int fa){
    	r=++tot;
    	T[r].key=w;
    	T[r].fa=fa;
    	T[r].son[0]=T[r].son[1]=0;
    }
    void rotat(int r,int kind){  //旋转,kind为1是右旋,为0是左旋
    	int y=T[r].fa;
    	T[y].son[!kind]=T[r].son[kind];
    	T[T[r].son[kind]].fa=y;
    	if(T[y].fa)
    	T[T[y].fa].son[T[T[y].fa].son[1]==y]=r;
    	T[r].fa=T[y].fa;
    	T[r].son[kind]=y;
    	T[y].fa=r;
    }
    void splay(int r,int goal){  //Splay调整,将结点r调整到goal下面(以r为根节点)
    	int y;
    	while(T[r].fa!=goal){
    		y=T[r].fa;
    		if(T[y].fa==goal) rotat(r,T[y].son[0]==r); //如果是左子树就右旋 右子树就左旋 
    		//如果现在的爸爸的爸爸就是目标的话,就旋转 
    		else{
    			int kind=T[T[y].fa].son[0]==y;
    			if(T[y].son[kind]==r){
    				rotat(r,!kind);
    				rotat(r,kind);
    			}
    			else{
    				rotat(y,kind);
    				rotat(r,kind);
    			}
    		}
    	}
    	if(goal==0) root=r; //更新根节点
    } 
    bool inser(int w){
    	int r=root;
    	while(T[r].son[w>T[r].key]){
    		if(T[r].key==w){   //如果w已经在树中
    			splay(r,0);   //移到树根
    			return false;  //返回0,不用继续插入了 
    		}
    		r=T[r].son[w>T[r].key]; //如果大的话,就插入右子树(1),小的话就插入左子树(0) 
    	}
    	newnode(T[r].son[w>T[r].key],w,r);  //插在r相应的子树里面   void newnode(int &r,int w,int fa)
    	splay(T[r].son[w>T[r].key],0);
    	//移动到树根
    	return true; 
    }
    int get_pre(int r){  //在左子树中找到最大的值(找前驱)
    	int temp=T[r].son[0];
    	if(temp==0) return INF;
    	while(T[temp].son[1])   //在左子树的右子树里面寻找 
    		temp=T[temp].son[1];
    	return T[r].key-T[temp].key;
    }
    int get_next(int r){  //在右子树中找到最小的值(找后继)
    	int temp=T[r].son[1];
    	if(temp==0) return INF;
    	while(T[temp].son[0])
    	temp=T[temp].son[0];
    	return T[temp].key-T[r].key;
    }
    int main(){
    	int n,x;
    	scanf("%d",&n);
    	int ans=0;
    	scanf("%d",&x);
    	ans=x;
    	newnode(root,x,0);
    	for(int i=1;i<n;i++){
    		scanf("%d",&x);
    		if(!inser(x)) continue;
    		ans+=min(get_pre(root),get_next(root));
    	}
    	printf("%d
    ",ans);
    return 0;
    }
    

    第四种方法:treap树

    每次取出新读入数据的前驱与后继,与该数据差值较小的就是。(注意若已有同一个数据,特判ans+=0)

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cmath>
    using namespace std;
    const int maxn = 100010;
    inline void qread(int &x) {
        x = 0;
        char ch = getchar();
    	int flag = 0;
        while(ch <'0' || ch >'9')        {
            if(ch =='-')    flag = 1;
            ch = getchar();
        }
        while(ch >='0'&& ch <='9')    x = 10 * x + ch - 48, ch = getchar();
        if(flag)    x = -x;
    }
    int rt = 0, tpn, v[maxn], l[maxn], r[maxn], R[maxn], sz[maxn], vn[maxn];
    inline void update(int x) {
        sz[x] = sz[l[x]] + sz[r[x]] + vn[x];
    }
    inline void zig(int &x) {
        int t = l[x];
        l[x] = r[t];
        r[t] = x;
        update(x);
        update(t);
        x = t;
    }
    inline void zag(int &x) {
        int t = r[x];
        r[x] = l[t];
        l[t] = x;
        update(x);
        update(t);
        x = t;
    }
    void insert(int &x, int w) {
        if(!x)    {
            x = ++tpn;
            v[x] = w;
            R[x] = rand();
            sz[x] = vn[x] = 1;
            return ;
        }
        if(w < v[x])    insert(l[x], w);
        else if(w > v[x])    insert(r[x], w);
        else            vn[x]++;
        update(x);
        if(l[x] && R[l[x]] < R[x])    zig(x);
        if(r[x] && R[r[x]] < R[x])    zag(x);
    }
    void pop(int &x, int w) {
        if(w < v[x])    pop(l[x], w);
        else if(w > v[x])    pop(r[x], w);
        else {
            if(vn[x] > 1)    vn[x]--;
            else if(!l[x] || !r[x])    x = l[x] | r[x];
            else if(R[l[x]] < R[r[x]])    zig(x), pop(x, w);
            else                        zag(x), pop(x, w);
        }
        update(x);
    }
    int ask(int x, int w){
        if(!x)        return -1;
        if(w < v[x])    return ask(l[x], w);
        if(w > v[x])    return ask(r[x], w);
        return     x;
    }
    int findk(int x, int k){
        if(k >= sz[l[x]] + 1 && k <= sz[l[x]] + vn[x])    return v[x];
        if(k <= sz[l[x]])    return findk(l[x], k);
        return     findk(r[x], k - sz[x] - vn[x]);
    }
    int findpre(int x, int w){
        int res = -0x3f3f3f3f;
        while(x){
            if(w <= v[x])    x = l[x];
            else            res = v[x], x = r[x];
        }
        return res;
    }
    int findnxt(int x, int w){
        int res = 0x3f3f3f3f;
        while(x){
            if(w < v[x])    res = v[x], x = l[x];
            else            x = r[x];
        }
        return res;
    }
    int main(void) {
        srand(11535);
        int n, ans;
        qread(n);
        qread(ans);
        insert(rt, ans);
        for(int i=2; i<=n; ++i){
            int x;
            qread(x);
            int l = findpre(rt, x), r = findnxt(rt, x);    
            if(ask(rt, x) != -1)    {insert(rt, x); continue;}
            insert(rt, x);
            ans += min(x - l, r - x);
        }    
        printf("%d
    ", ans);
    }
    

      还有第五种方法是线段树、第六种替罪羊树(不知道没写了)

    1566:宠物收养所

    这道题和前面一道很相似,都是需要计算相差最小的前驱和后继,适合使用treap或者splay这样的数据结构

    这个跟 营业额统计 那题差不多,多了个标记。标记一下当前这个树里的是人还是狗。判断一下当前操作的与树里的是不是同种生物,然后相应做出处理就好了。
    首先是treap的做法

    #include<bits/stdc++.h>
    using namespace std;
    const int N=80005;
    const int mod=1000000;
    const int inf=1e9;
    int n,ans,a,b,R,sum,num[N];
    int ch[N][2],size[N],val[N],rd[N];
    void rotate(int &q,int d)
    {
        int k=ch[q][d];
        ch[q][d]=ch[k][d^1];
        ch[k][d^1]=q;
        size[k]=size[q];
        size[q]=size[ch[q][0]]+size[ch[q][1]]+1;
        q=k;
    }
    void ins(int &q,int x)
    {
        if(!q)
        {
            q=++sum;
            size[q]=1;val[q]=x;
            rd[q]=rand(); return;
        }
        size[q]++;
        if(val[q]<x)
        {
            ins(ch[q][1],x);
            if(rd[q]>rd[ch[q][1]]) rotate(q,1);
        }
        else
        {
            ins(ch[q][0],x);
            if(rd[q]>rd[ch[q][0]]) rotate(q,0);
        }
    }
    void del(int &q,int x)
    {
        if(!q) return;
        if(val[q]==x)
        {
            if(ch[q][0]==0||ch[q][1]==0) q=ch[q][0]+ch[q][1];
            else if(rd[ch[q][0]]<rd[ch[q][1]]) rotate(q,0),del(q,x);
            else rotate(q,1),del(q,x);
        }
        else
        {
            size[q]--;
            if(val[q]>x) del(ch[q][0],x);
            else del(ch[q][1],x);
        }
    }
    int qq(int q,int x)
    {
        if(!q) return -inf;
        if(val[q]>x) return qq(ch[q][0],x);
        else return max(val[q],qq(ch[q][1],x));
    }
    int hq(int q,int x)
    {
        if(!q) return inf;
        if(val[q]<x) return hq(ch[q][1],x);
        else return min(val[q],hq(ch[q][0],x));
    }
    int main()
    {
        scanf("%d",&n);int c=-1;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a,&b);
            if(c==a) ins(R,b);
            else if(size[R]){
                int hhh=qq(R,b),ggg=hq(R,b);
                if(b-hhh<=ggg-b) ans=(ans+b-hhh)%mod,del(R,hhh);
                else ans=(ans+ggg-b)%mod,del(R,ggg);
            }
            else c=a,ins(R,b);
        }
        printf("%d",ans);
        return 0;
    } 
    

    第二种方法:splay树

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<vector>
    #include<algorithm>
    using namespace std;
    #define MAX 200000
    #define MOD 1000000
    int tot;
    inline int read()
    {
    	register int x=0,t=1;
    	register char ch=getchar();
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-'){t=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
    	return x*t;
    }
    struct Node
    {
    	int ch[2];
    	int val;
    	int ff;
    }t[MAX];
    int root;
    inline void rotate(int x)
    {
    	int y=t[x].ff;
    	int z=t[y].ff;
    	int k=(x==t[y].ch[1]);
    	t[z].ch[y==t[z].ch[1]]=x;
    	t[x].ff=z;
    	t[y].ch[k]=t[x].ch[k^1];
    	t[t[x].ch[k^1]].ff=y;
    	t[x].ch[k^1]=y;
    	t[y].ff=x;
    }
    inline void splay(int x,int goal)
    {
    	//if(x==0)return;
    	while(t[x].ff!=goal)
    	{
    		int y=t[x].ff;
    		int z=t[y].ff;
    		if(z!=goal)
    			(t[z].ch[0]==y)^(t[y].ch[0]==x)?rotate(x):rotate(y);
    		rotate(x);
    	}
    	if(goal==0)root=x;
    }
    inline void insert(int x)
    {
    	int u=root,ff=0;
    	while(u&&t[u].val!=x)
    	{
    		ff=u;
    		u=t[u].ch[t[u].val<x];
    	}
    	if(u);
    	else
    	{
    		u=++tot;
    		if(ff)t[ff].ch[t[ff].val<x]=u;
    		t[u].ff=ff;
    		t[u].ch[0]=t[u].ch[1]=0;
    		t[u].val=x;
    	}
    	splay(u,0);
    }
    inline void find(int x)
    {
    	int u=root;
    	if(!u)return;
    	while(t[u].ch[x>t[u].val]&&x!=t[u].val)
    		u=t[u].ch[x>t[u].val];
    	splay(u,0);
    }
    inline int Next(int x,int f)
    {
    	find(x);
    	int u=root;
    	if(t[u].val>=x&&f)return u;
    	if(t[u].val<=x&&!f)return u;
    	u=t[u].ch[f];
    	while(t[u].ch[f^1])u=t[u].ch[f^1];
    	return u;
    }
    inline int Next_une(int x,int f)
    {
    	find(x);
    	int u=root;
    	if(t[u].val>x&&f)return u;
    	if(t[u].val<x&&!f)return u;
    	u=t[u].ch[f];
    	while(t[u].ch[f^1])u=t[u].ch[f^1];
    	return u;
    }
    inline void Delete(int x)
    {
    	int lt=Next_une(x,0);
    	int nt=Next_une(x,1);
    	splay(lt,0);splay(nt,lt);
    	t[nt].ch[0]=0;
    }
    int main()
    {
    	int n=read();
    	int cnt=0,ans=0;
    	insert(+214748364);
    	insert(-214748364);
    	while(n--)
    	{
    		int k=read(),x=read();
    		if(x==1)
    		    x=1;
    		if(cnt==0)//空树
    			insert(x);
    		if(cnt>0)//宠物树
    		{
    			if(k==0)insert(x);
    			else//新来顾客
    			{
    				int a1=t[Next(x,0)].val;//前驱
    				int a2=t[Next(x,1)].val;//后继
    				if(abs(a1-x)<=abs(a2-x))
    				{
    					ans+=abs(a1-x);
    					Delete(a1);
    				}
    				else
    				{
    					(ans+=abs(a2-x))%=MOD;
    					Delete(a2);
    				}
    			}
    		}
    		if(cnt<0)//顾客树
    		{
    			if(k==1)insert(x);
    			else//新来宠物
    			{
    				int a1=t[Next(x,0)].val;
    				int a2=t[Next(x,1)].val;
    				if(abs(a1-x)<=abs(a2-x))
    				{
    					(ans+=abs(a1-x))%=MOD;
    					Delete(a1);
    				}
    				else
    				{
    					(ans+=abs(a2-x))%=MOD;
    					Delete(a2);
    				}
    			}
    		}
    		cnt=cnt+(k==0?1:-1);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

      

    1567:郁闷的出纳员

     其实看题目就能够明白:需要做的事有增加或减少每一个节点的值,增加节点、删除节点,查询排名为第k的人的值

    节点的值是会动态改变,还可能动态删除的,而重点是这道题想问当前工资第k多的员工所拿的工资数
    先写一个最简单的vector https://www.sogou.com/link?url=hedJjaC291P3yGwc7N55kLSc2ls_Ks2xYJXKjZDwcU0p1wk5xGC9fwNZoNd2gwAGIeZ8aQ291kY.
    /*
    vector通过lower_bound和insert操作能够维护一个有序递减/递增的线性表
    insert复杂度虽然是O(n),实际表现却非常快(可以看做sqrt(n)),配合lower_bound能够做到许多事情
    在这道题中,我们重载了lower_bound的<运算符,维护一个单调递减的序列
    ps
    erase的复杂度为O(n),因为是区间删除,我们要避免用erase操作,注意到删除的区间是序列中最小的一段区间,考虑用O(1)的pop_back
    pop_back的复杂度是O(1),元素总数不超过100000,故删除操作总复杂度为O(N)
    查询元素总数时,我们也不用STL的size()(单次复杂度O(N)),而是手动维护一个siz变量

     但是我对delta偏移的用法还不是很懂

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<stack>
    #include<cstdio>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    using namespace std;
    const int maxn=1e6+10;
    const int INF=0x3fffffff;
    typedef long long LL;
    typedef unsigned long long ull;
    int n,m;
    int k;
    vector<int> q;
    bool cmp(int a,int b) {
    	return a>b;
    }
    int delta=0; //用这个记录偏移 就是增加或者减小的工资 
    int main(){
    	scanf("%d %d",&n,&m);
    	char op;
    	int size=0,ans=0;  //手动维护集合大小 
    	for(int i=0;i<n;i++){
    		scanf(" %c",&op);
    		scanf("%d",&k);
    		switch(op){
    			case 'I':{
    				if(k>=m){
    					q.insert(lower_bound(q.begin(),q.end(),k-delta,cmp),k-delta);  //为什么插入的是k-delta 
    					size++;
    				}
    				break;
    			}
    			case 'A':
    			 delta+=k;break;
    			case 'S':{
    				delta-=k;
    				int it=upper_bound(q.begin(),q.end(),m-delta,cmp)-q.begin();   //为什么比较的是m-delta 
    				while(size!=it) {
    					q.pop_back();
    					ans++;
    					size--;
    				}
    				break;
    			}
    			case 'F':{
    				if(size<k) printf("-1
    ");
    				else printf("%d
    ",q[k-1]+delta);
    				break;
    			}
    	}
    	}
    	printf("%d
    ",ans);
    return 0;
    }
    

    第二种方法:splay

    #include<cstdio>
    #define maxn 100009
    using namespace std;
    struct splay{
        int l, r, fa, size, v, time;
    }node[maxn];
    int root = 0, cnt = 0, change = 0, p = 0, n, small;
    inline void update(int x){node[x].size = node[node[x].l].size + node[node[x].r].size + node[x].time;}
    void zig(int x){
        int F = node[x].fa, G = node[F].fa;
        if (G){
            if (node[G].l == F) node[G].l = x;
            else node[G].r = x;
        }
        node[x].fa = G;
        node[F].l = node[x].r;
        if (node[x].r) node[node[x].r].fa = F;
        node[F].fa = x;
        node[x].r = F;
    }
    void zag(int x){
        int F = node[x].fa, G = node[F].fa;
        if (G){
            if (node[G].l == F) node[G].l = x;
            else node[G].r = x;
        }
        node[x].fa = G;
        node[F].r = node[x].l;
        if (node[x].l) node[node[x].l].fa = F;
        node[F].fa = x;
        node[x].l = F;
    }
    void Splay(int x, int s = 0){
        while (node[x].fa != s){
            int F = node[x].fa, G = node[F].fa;
            if (G == s){
                if (node[F].l == x) zig(x); else zag(x);
                update(F);
                break;
            }
            else{
                if (node[F].l == x){
                    if (node[G].l == F){zig(F); zig(x);}
                    else{zig(x);zag(x);}
                }
                else{
                    if (node[G].r == F){zag(F); zag(x);}
                    else{zag(x); zig(x);}
                }
                update(G);
                update(F);
            }
        }
        update(x);
        if (!s) root = x;
    }
    int find(int x){
        int p = root;
        while (p && node[p].v != x){
        if (x > node[p].v) p = node[p].r; else p = node[p].l;
        }
        if (p) Splay(p);
        return p;
    }
    void insert(int x){
        if (!root){node[++cnt] = (splay){0, 0, 0, 1, x, 1}; root = cnt; return;}
        int p = root, p2;
        while (p){
            if (x == node[p].v) {++node[p].time;update(p); Splay(p);break;}
            else if (x > node[p].v) p2 = node[p].r;
            else p2 = node[p].l;
            if (!p2){
                node[++cnt] = (splay){0, 0, p, 1, x, 1};
                if (x > node[p].v) node[p].r = cnt;
                else node[p].l = cnt;
                update(p);
                Splay(cnt);
                break;
            }
            p = p2;
        }
    }
    int getKth(int k){
        int p = root;
        while (k){
            int size = node[node[p].l].size, time = node[p].time;
            if (size + time < k) {p = node[p].r; k -= size + time;}
            else if (size >= k) p =  node[p].l;
            else return node[p].v;
        }
    }
    void del(){
        int p = root, p2 = root, ch = small - change;
        while(p){
            if (node[p].v < ch) p = node[p].r;
            else{p2 = p; p = node[p].l;}
        }
        if (node[p2].v < ch) {root = 0;return;}
        Splay(p2);
        node[p2].l = 0;
        update(p2);
    }
    int read(){
        char c;
        while (c = getchar(), c < '0' || c > '9');
        int x = c - '0';
        while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0';
        return x;
    }
    int main(){
        char c; int x;
        node[0] = (splay){0, 0, 0, 0, 0, 0};
        n = read(); small = read();
        while(n--){
            while (c = getchar(), !(c >= 'A' && c <= 'Z'));
            x = read();
            switch(c){
                case 'I':if (x >= small) {++p;insert(x - change);};break;
                case 'A':change += x;break;
                case 'S':change -= x; del();break;
                case 'F':if (x > node[root].size) printf("-1
    ");
                else printf("%d
    ", getKth(node[root].size - x + 1) + change);break;
            }
        }
        printf("%d
    ", p - node[root].size);
        return 0;
    } 
    

      

    1568:普通平衡树

    这是一道模板题。

    您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

    1、插入 xx 数;

    2、删除 xx 数(若有多个相同的数,因只删除一个);

    3、查询 xx 数的排名(若有多个相同的数,因输出最小的排名);

    4、查询排名为 xx 的数;

    5、求 xx 的前趋(前趋定义为小于 xx,且最大的数);

    6、求 xx 的后继(后继定义为大于 xx,且最小的数)。

    treap的模板

    https://www.cnblogs.com/Y-Knightqin/p/12252930.html 
    #include <bits/stdc++.h>
    #define maxn 100010
    #define inf 0x3f3f3f3f
    using namespace std;
    //https://www.cnblogs.com/Y-Knightqin/p/12252930.html 
    int key[maxn],cnt[maxn],ran[maxn],siz[maxn],son[maxn][2],op,n,num=0,x,root=0;
    void pushup(int x)
    {
        siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x];
    }
    void rotate(int &x,int op)
    {
        int p=son[x][!op];
        son[x][!op]=son[p][op];
        son[p][op]=x;
        pushup(x);
        pushup(p);
        x=p;
    }
    void insert(int &k,int x)
    {
        if (k==0)
        {
            k=++num;
            cnt[k]=1;
            key[k]=x;
            ran[k]=rand();
            siz[k]=1;
            return;
        }
        else if (key[k]==x)
        {
            cnt[k]++;
            siz[k]++;
            return;
        }
        int op=(x>key[k]);
        insert(son[k][op],x);
        if (ran[son[k][op]]<ran[k]) rotate(k,!op);
        pushup(k);
    }
    void _delete(int &k,int x)
    {
        if (k==0) return;
        if (x!=key[k])
        {
            int op=(x>key[k]);
            _delete(son[k][op],x);
            pushup(k);
            return;
        }
        if (cnt[k]>1)
        {
            cnt[k]--;
            siz[k]--;
            pushup(k);
            return;
        }
        if (!son[k][0]&&son[k][1])
        {
            rotate(k,0);
            _delete(son[k][0],x);
        }
        else if (son[k][0] && !son[k][1])
        {
            rotate(k,1);
            _delete(son[k][1],x);
        }
        else if (!son[k][0] && !son[k][1])
        {
            cnt[k]--;
            siz[k]--;
            if (cnt[k]==0) k=0;
        }
        else
        {
            int op=(ran[son[k][0]]>ran[son[k][1]]);
            rotate(k,!op);
            _delete(son[k][!op],x);
        }
        pushup(k);
    }
    int rank(int k,int x)
    {
        if (k==0) return 0;
        if (key[k]==x) return siz[son[k][0]]+1;
        if (key[k]>x) return rank(son[k][0],x);
        return siz[son[k][0]]+cnt[k]+rank(son[k][1],x);
    }
    int find(int k,int x)
    {
        if (k==0) return 0;
        if (siz[son[k][0]]>=x) return find (son[k][0],x);
        else if (siz[son[k][0]]+cnt[k]<x) return find (son[k][1],x-siz[son[k][0]]-cnt[k]);
        else return key[k];
    }
    int lowerbound(int k,int x)
    {
        if (k==0) return -inf;
        if (key[k]>=x) return lowerbound(son[k][0],x);
            else return max(key[k],lowerbound(son[k][1],x));
    }
    int upperbound(int k,int x)
    {
        if (k==0) return inf;
        if (key[k]<=x) return upperbound(son[k][1],x);
            else return min(key[k],upperbound(son[k][0],x));
    }
    int main()
    {
        cin>>n;
        while (n--)
        {
            scanf("%d%d",&op,&x);
            switch(op)
            {
                case 1:insert(root,x);break;
                case 2:_delete(root,x);break;
                case 3:printf("%d
    ",rank(root,x));break;
                case 4:printf("%d
    ",find(root,x));break;
                case 5:printf("%d
    ",lowerbound(root,x));break;
                case 6:printf("%d
    ",upperbound(root,x));break;
            }
        }
        return 0;
     }
    

      里面还写了一个懒人版treap,用vector实现的

    #include <bits/stdc++.h>
    #define debug freopen("r.txt","r",stdin)
    #define mp make_pair
    #define ri register int
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int maxn = 4e5+5;
    const int INF = 0x3f3f3f3f; 
    const int mod = 998244353;
    inline ll read(){ll s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return s*w;}
    ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
    vector<int>v;
    int t,opt,x;
    int main()
    {
        t=read();
        while(t--)
        {
            opt=read(),x=read();
            if(opt==1) v.insert(lower_bound(v.begin(),v.end(),x),x);
            if(opt==2) v.erase (lower_bound(v.begin(),v.end(),x));
            if(opt==3) printf("%d
    ",lower_bound(v.begin(),v.end(),x)-v.begin()+1);
            if(opt==4) printf("%d
    ",v[x-1]);
            if(opt==5) printf("%d
    ",v[lower_bound(v.begin(),v.end(),x)-v.begin()-1]);
            if(opt==6) printf("%d
    ",v[upper_bound(v.begin(),v.end(),x)-v.begin()]);
        }
        return 0;
    }
    

      

  • 相关阅读:
    Java.io.outputstream.PrintStream:打印流
    Codeforces 732F. Tourist Reform (Tarjan缩点)
    退役了
    POJ 3281 Dining (最大流)
    Light oj 1233
    Light oj 1125
    HDU 5521 Meeting (最短路)
    Light oj 1095
    Light oj 1044
    HDU 3549 Flow Problem (dinic模版 && isap模版)
  • 原文地址:https://www.cnblogs.com/shirlybaby/p/13775997.html
Copyright © 2011-2022 走看看