伸展树-入门

参考博客

博客链接

网上资料不少,留下自己AC代码方便以后回看,用的spt模板是博客里的

1、营业额统计

题目链接
题意:

求最小的营业额波动总和
最小的营业额波动=min(|x-y|),y是之前某天营业额

解法:

插入某个数,找前序以及后序即可

代码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <vector>
#define rep(i,n) for(i=0;i<n;i++)
#define cle(x) memset(x,0,sizeof(x))

#define ll long long
#define keyTree (ch[ ch[root][1] ][0])
const int maxn=100000+5;
using namespace std;
struct SplayTree{
     int ch[maxn][2];
     int pre[maxn];
     int root,top1;
     inline void Rotate(int x,int f)
     {
          //f=1 右旋 f=0 左旋
          int y=pre[x];
          ch[y][!f]=ch[x][f];
          pre[ ch[x][f] ]=y;
          pre[x]=pre[y];
          if(pre[x])ch[ pre[y] ][ ch[pre[y]][1]==y]=x;
          ch[x][f]=y;
          pre[y]=x;
     }
     inline void Splay(int x,int goal) {
          while(pre[x] != goal) {
               if(pre[pre[x]] == goal) {
                    Rotate(x , ch[pre[x]][0] == x);
               } else {
                    int y = pre[x] , z = pre[y];
                    int f = (ch[z][0] == y);
                    if(ch[y][f] == x) {
                         Rotate(x , !f) , Rotate(x , f);
                    } else {
                         Rotate(y , f) , Rotate(x , f);
                    }
               }
          }
          if(goal == 0) root = x;
     }

     inline void NewNode(int &x,int c)
     {
          x=++top1;
          ch[x][0]=ch[x][1]=pre[x]=0;
          val[x]=c;
     }
     inline void Insert(int k)
     {
         int r=root;
         if(r==0)
         {
             ch[0][0]=ch[0][1]=pre[0]=0;
             NewNode(root,k);
             return;
         }
         while(ch[r][val[r]<k])
         {
             r=ch[r][val[r]<k];
         }
         NewNode(ch[r][val[r]<k],k);
         pre[ch[r][val[r]<k]]=r;
         Splay(ch[r][val[r]<k],0);
     }
     inline int Getpre(int r)
     {
         while(ch[r][1])
             r=ch[r][1];
         return val[r];
     }
     inline int Getflo(int r)
     {
         while(ch[r][0])
             r=ch[r][0];
         return val[r];
     }
     inline void Work(int n)
     {
         root=top1=0;
         ll ans=0;
         for(int i=1;i<=n;i++)
         {
             int k;
             if(scanf("%d",&k)==EOF)k=0;
             Insert(k);
             if(i==1)ans+=k;
             else
             {
                 int left=ch[root][0];
                 int right=ch[root][1];
                 int temp=0x3fffffff;
                 if(left){
                     temp=min(temp,k-Getpre(left));
                 }
                 if(right){
                     temp=min(temp,Getflo(right)-k);
                 }
                 ans+=(ll)temp;
             }
         }
         printf("%I64d\n",ans);
     }
     int val[maxn];
}spt;
int main()
{
#ifndef ONLINE_JUDGE
     freopen("in.txt","r",stdin);
     //freopen("out.txt","w",stdout);
#endif
    int n;
    while(~scanf("%d",&n))
    {
        spt.Work(n);
    }
    return 0;
}

2、Double Queue (poj 3481)

题目链接
题意:

1:添加优先级为p的k号机器
2:去掉队列里优先级最高的机器
3:去掉队列里优先级最低的机器

解法:

2:min=while(ch[root][0]),splay(min,0),并删掉即可
3: 类似,伸展后无右子树

代码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <vector>
#define rep(i,n) for(i=0;i<n;i++)
#define cle(x) memset(x,0,sizeof(x))

#define ll long long
const int maxn=1000000+5;
using namespace std;
#define keyTree (ch[ ch[root][1] ][0])
struct SplayTree{
     int ch[maxn][2];
     int pre[maxn];
     int root,top1;
     inline void Rotate(int x,int f)
     {
          //f=1 右旋 f=0 左旋
          int y=pre[x];
          ch[y][!f]=ch[x][f];
          pre[ ch[x][f] ]=y;
          pre[x]=pre[y];
          if(pre[x])ch[ pre[y] ][ ch[pre[y]][1]==y]=x;
          ch[x][f]=y;
          pre[y]=x;
     }
     inline void Splay(int x,int goal) {
          while(pre[x] != goal) {
               if(pre[pre[x]] == goal) {
                    Rotate(x , ch[pre[x]][0] == x);
               } else {
                    int y = pre[x] , z = pre[y];
                    int f = (ch[z][0] == y);
                    if(ch[y][f] == x) {
                         Rotate(x , !f) , Rotate(x , f);
                    } else {
                         Rotate(y , f) , Rotate(x , f);
                    }
               }
          }
          if(goal == 0) root = x;
     }
     inline void NewNode(int &x,int c,int p)
     {
          x=++top1;
          ch[x][0]=ch[x][1]=pre[x]=0;
          val[x]=c;
          ip[x]=p;
     }
     inline void Insert(int k,int p)
     {
         int r=root;
         if(r==0)
         {
             ch[0][0]=ch[0][1]=pre[0]=ip[0]=0;
             NewNode(root,k,p);
             return;
         }
         while(ch[r][val[r]<k])
         {
             r=ch[r][val[r]<k];
         }
         NewNode(ch[r][val[r]<k],k,p);
         pre[ch[r][val[r]<k]]=r;
         Splay(ch[r][val[r]<k],0);
     }
     inline int Getmin(int r)
     {
         while(ch[r][0])r=ch[r][0];
         Splay(r,0);
         return ip[r];
     }
     inline int Getmax(int r)
     {
         while(ch[r][1])r=ch[r][1];
         Splay(r,0);
         return ip[r];
     }
     inline void Work()
     {
         root=top1=0;
         int op;
         while(~scanf("%d",&op)){
             int k,p;
             if(op==1){
                 scanf("%d%d",&k,&p);
                 Insert(p,k);
             }
             else if(op==3)
             {
                 int temp=ip[root];
                 int left=ch[root][0];
                 if(left)
                     temp=Getmin(left);

                 int right=ch[root][1];
                 pre[right]=0;
                 root=right;

                 printf("%d\n",temp);
             }
             else if(op==2)
             {
                 int temp=ip[root];
                 int right=ch[root][1];
                 if(right)
                     temp=Getmax(right);

                 int left=ch[root][0];
                 pre[left]=0;
                 root=left;

                 printf("%d\n",temp);
             }
             else{
                 break;
             }
            // debug();
         }
     }
     int val[maxn];
     int ip[maxn];
}spt;
int main()
{
#ifndef ONLINE_JUDGE
     freopen("in.txt","r",stdin);
     //freopen("out.txt","w",stdout);
#endif
    spt.Work();
    return 0;
}

最后献上 poj 3468段更新 by notonlysuccess

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <vector>
#define rep(i,n) for(i=0;i<n;i++)
#define cle(x) memset(x,0,sizeof(x))

#define ll long long
#define keyTree (ch[ ch[root][1] ][0])
const int maxn=200000+5;
using namespace std;
struct SplayTree{
    int sz[maxn];
    int ch[maxn][2];
    int pre[maxn];
    int root,top1,top2;
    int ss[maxn],que[maxn];

    inline void Rotate(int x,int f)
    {
        //f=1 右旋 f=0 左旋
        int y=pre[x];
        push_down(y);
        push_down(x);
        ch[y][!f]=ch[x][f];
        pre[ ch[x][f] ]=y;
        pre[x]=pre[y];
        if(pre[x])ch[ pre[y] ][ ch[pre[y]][1]==y]=x;
        ch[x][f]=y;
        pre[y]=x;
        push_up(y);
    }
    inline void Splay(int x,int goal) {
        push_down(x);
        while(pre[x] != goal) {
            if(pre[pre[x]] == goal) {
                Rotate(x , ch[pre[x]][0] == x);
            } else {
                int y = pre[x] , z = pre[y];
                int f = (ch[z][0] == y);
                if(ch[y][f] == x) {
                    Rotate(x , !f) , Rotate(x , f);
                } else {
                    Rotate(y , f) , Rotate(x , f);
                }
            }
        }
        push_up(x);
        if(goal == 0) root = x;
    }
    inline void RotateTo(int k,int goal) {//把第k位的数转到goal下边
        int x = root;
        push_down(x);
        while(sz[ ch[x][0] ] != k) {
            if(k < sz[ ch[x][0] ]) {
                x = ch[x][0];
            } else {
                k -= (sz[ ch[x][0] ] + 1);
                x = ch[x][1];
            }
            push_down(x);
        }
        Splay(x,goal);
    }
    inline void NewNode(int &x,int c)
    {
        x=++top1;
        ch[x][0]=ch[x][1]=pre[x]=0;
        sz[x]=1;
        val[x]=sum[x]=c;
        add[x]=0;
    }
    inline void push_down(int x)
    {
        if(add[x])
        {
            val[x]+=add[x];
            int left=ch[x][0];
            int right=ch[x][1];
            add[left]+=add[x],add[right]+=add[x];
            sum[left]+=(ll)sz[left]*add[x];
            sum[right]+=(ll)sz[right]*add[x];
            add[x]=0;
        }
    }
    inline void push_up(int x)
    {
        int left=ch[x][0];
        int right=ch[x][1];
        sz[x]=1+sz[left]+sz[right];
        sum[x]=add[x]+val[x]+sum[left]+sum[right];
    }
    inline void makeTree(int &x,int l,int r,int f)
    {
        if(l>r)
            return;
        int mid=(l+r)>>1;
        NewNode(x,num[mid]);
        makeTree(ch[x][0],l,mid-1,x);//左子树
        makeTree(ch[x][1],mid+1,r,x);
        pre[x]=f;
        push_up(x);
    }
    inline void init(int n)
    {
        ch[0][0]=ch[0][1]=pre[0]=sz[0]=0;
        add[0]=sum[0]=0;
        root=top1=0;
        NewNode(root,-1);
        NewNode(ch[root][1],-1);
        pre[top1]=root;
        sz[root]=2;
        for(int i=0;i<n;i++)
            scanf("%d",&num[i]);
        makeTree(keyTree,0,n-1,ch[root][1]);
        push_up(ch[root][1]);
        push_up(root);
    }
    inline void update()
    {
        int l,r,c;
        scanf("%d%d%d",&l,&r,&c);
        RotateTo(l-1,0);
        RotateTo(r+1,root);
        add[keyTree]+=c;
        sum[keyTree]+=(ll)c*sz[keyTree];
    }
    inline void query()
    {
        int l,r;
        scanf("%d%d",&l,&r);
        RotateTo(l-1,0);
        RotateTo(r+1,root);
        printf("%I64d\n",sum[keyTree]);
    }
    int num[maxn];
    int val[maxn];
    int add[maxn];
    ll sum[maxn];
}spt;
int main()
{
#ifndef ONLINE_JUDGE
     freopen("in.txt","r",stdin);
     //freopen("out.txt","w",stdout);
#endif
    int n,m;
    scanf("%d%d",&n,&m);
    spt.init(n);
    while(m--)
    {
        char op[10];
        scanf("%s",&op);
        if(op[0]=='Q')
            spt.query();
        else
            spt.update();
    }
    return 0;
}

未完,待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值