zoukankan      html  css  js  c++  java
  • splay tree成段更新,成段查询poj3466

    线段树入门题,换成splay tree 来搞搞。

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    #define MAXN 200100
    
    long long Add[MAXN];//延迟标记
    
    struct Splay_Tree
    {
        int cnt, rt;//cnt为节点数,rt == root
    
        struct Tree{
            long long K;
            long long sumk;
            int key;//关键字
            int num, size;//num是这个节点有多少重复,size是以这个节点为根的子树大小。
            int fa, son[2];
        }T[MAXN];
    
        inline void init()
        {
            cnt = 0;//初始化超级根节点(标记为0的节点)
            T[0].size = 0;
            T[0].sumk = 0;
            T[0].K = 0;
            rt = 0;
            memset(Add,0,sizeof(Add));
        }
        inline void PushUp(int x)
        {
            T[x].size=T[T[x].son[0]].size+T[T[x].son[1]].size+T[x].num;
            T[x].sumk=T[T[x].son[0]].sumk+T[T[x].son[1]].sumk+T[x].K;
        }
    
        inline void PushDown(int x)
        {
            if(Add[x])
            {
                if(T[x].son[0])//
                {
                    T[T[x].son[0]].K += Add[x];
                    T[T[x].son[0]].sumk += T[T[x].son[0]].size*Add[x];
                    Add[T[x].son[0]]+=Add[x];
                }
                if(T[x].son[1])
                {
                    T[T[x].son[1]].K+=Add[x];
                    T[T[x].son[1]].sumk += T[T[x].son[1]].size*Add[x];
                    Add[T[x].son[1]]+=Add[x];
                }
                Add[x]=0;//不管子节点有没有,这层一定往下推,没有子节点相当于标记无效。
            }
        }
    
        inline int Newnode(int key, int fa,int K) //新建一个节点并返回
        {
            ++cnt;
            T[cnt].K = T[cnt].sumk = K;
            T[cnt].key=key;
            T[cnt].num=T[cnt].size=1;
            T[cnt].fa=fa;
            T[cnt].son[0]=T[cnt].son[1]=0;
            return cnt;
        }
    
        inline void Rotate(int x, int p) //0左旋 1右旋
        {
            int y=T[x].fa;
            PushDown(y);//这里是不是必须的,我感觉从小往上不需要往上推
            PushDown(x);
            T[y].son[!p]=T[x].son[p];
            T[T[x].son[p]].fa=y;
            T[x].fa=T[y].fa;
            if(T[x].fa)
                T[T[x].fa].son[T[T[x].fa].son[1] == y]=x;
            T[x].son[p]=y;
            T[y].fa=x;
            PushUp(y);
            PushUp(x);
        }
    
        void Splay(int x, int To) //将x节点移动到To的子节点中
        {
            while(T[x].fa != To)
            {
                if(T[T[x].fa].fa == To)
                    Rotate(x, T[T[x].fa].son[0] == x);
                else
                {
                    int y=T[x].fa, z=T[y].fa;
                    int p=(T[z].son[0] == y);
                    if(T[y].son[p] == x)
                        Rotate(x, !p), Rotate(x, p); //之字旋
                    else
                        Rotate(y, p), Rotate(x, p); //一字旋
                }
            }
            if(To == 0) rt=x;
        }
    
        int GetPth(int p, int To) //返回第p小的节点 并移动到To的子节点中
        {
            if(!rt || p > T[rt].size) return 0;
            int x=rt;
            while(x)
            {
                PushDown(x);
                if(p >= T[T[x].son[0]].size+1 && p <= T[T[x].son[0]].size+T[x].num)
                    break;
                if(p > T[T[x].son[0]].size+T[x].num)
                {
                    p-=T[T[x].son[0]].size+T[x].num;
                    x=T[x].son[1];
                }
                else
                    x=T[x].son[0];
            }
            Splay(x, 0);
            return x;
        }
    
        int Find(int key) //返回值为key的节点 若无返回0 若有将其转移到根处
        {
            if(!rt) return 0;
            int x=rt;
            while(x)
            {
                PushDown(x);
                if(T[x].key == key) break;
                x=T[x].son[key > T[x].key];
            }
            if(x) Splay(x, 0);
            return x;
        }
    
        int Prev() //返回根节点的前驱 非重点
        {
            if(!rt || !T[rt].son[0]) return 0;
            int x=T[rt].son[0];
            while(T[x].son[1])
            {
                PushDown(x);
                x=T[x].son[1];
            }
            Splay(x, 0);
            return x;
        }
    
        int next() //返回根结点的后继 非重点
        {
            if(!rt || !T[rt].son[1]) return 0;
            int x=T[rt].son[1];
            while(T[x].son[0])
            {
                PushDown(x);
                x=T[x].son[0];
            }
            Splay(x, 0);
            return x;
        }
    
        void Insert(int key,int K) //插入key值
        {
            if(!rt)
                rt=Newnode(key, 0, K);
            else
            {
                int x=rt, y=0;
                while(x)
                {
                    PushDown(x);
                    y=x;
                    if(T[x].key == key)
                    {
                        T[x].num++;
                        T[x].size++;
                        break;
                    }
                    T[x].size++;//既然一定调整
                    x=T[x].son[key > T[x].key];
                }
                if(!x)
                    x = T[y].son[key > T[y].key] = Newnode(key, y, K);
                Splay(x, 0);
            }
        }
    
        void Delete(int key) //删除值为key的节点1个
        {
            int x=Find(key);
            if(!x) return;
            if(T[x].num>1)
            {
                T[x].num--;
                PushUp(x);
                return;
            }
            int y=T[x].son[0];
            while(T[y].son[1])
                y=T[y].son[1];
            int z=T[x].son[1];
            while(T[z].son[0])
                z=T[z].son[0];
            if(!y && !z)
            {
                rt=0;
                return;
            }
            if(!y)
            {
                Splay(z, 0);
                T[z].son[0]=0;
                PushUp(z);
                return;
            }
            if(!z)
            {
                Splay(y, 0);
                T[y].son[1]=0;
                PushUp(y);
                return;
            }
            Splay(y, 0);
            Splay(z, y);
            T[z].son[0]=0;
            PushUp(z);
            PushUp(y);
        }
    
        int GetRank(int key) //获得值<=key的节点个数 并将其转移到根处 若<key只需将<=换为<
        {
            if(!rt) return 0;
            int x=rt, ret=0, y=0;
            while(x)
            {
                y=x;
                if(T[x].key <= key)
                {
                    ret += T[T[x].son[0]].size + T[x].num;
                    x=T[x].son[1];
                }
                else
                    x=T[x].son[0];
            }
            Splay(y, 0);
            return ret;
        }
    
    //    这个删除太丑了
    //    void Delete(int l, int r) //删除值在[l, r]中的所有节点 l!=r
    //    {
    //        if(!Find(l)) Insert(l);// 你这样写真的好吗? 泥煤
    //        int p=Prev();
    //        if(!Find(r)) Insert(r);
    //        int q=next();
    //        if(!p && !q)
    //        {
    //            rt=0;
    //            return;
    //        }
    //        if(!p)
    //        {
    //            T[rt].son[0]=0;
    //            PushUp(rt);
    //            return;
    //        }
    //        if(!q)
    //        {
    //            Splay(p, 0);
    //            T[rt].son[1]=0;
    //            PushUp(rt);
    //            return;
    //        }
    //        Splay(p, q);
    //        T[p].son[1]=0;
    //        PushUp(p);
    //        PushUp(q);
    //    }
    }spt;
    
    int main() {
        int n,q;
        scanf("%d%d",&n,&q);
        spt.init();
        for(int i=1;i<=n;i++)
        {
            int tmp;
            scanf("%d",&tmp);
            spt.Insert(i, tmp);
        }
        for(int i=0;i<q;i++)
        {
            getchar();
            char sign;
            scanf("%c",&sign);
            long long ans=0;
            if(sign == 'Q')
            {
                int a,b;
                scanf("%d%d",&a,&b);
                if(a==b)
                {
                    int id = spt.Find(a);
                    // mark
                    ans = spt.T[id].K;
                    //cout<<spt.T[id].K<<endl;
                }
                else
                {
                    int ida,idb;
                    idb = spt.Find(b);//在这题,因为点没有删除,所以点的标号和splaytree中标号一致。
                    ida = spt.Find(a);//但是有lazy标记,所以还是得找一遍,可以把标记往下推。
                    spt.Splay(idb, ida);
                    int idson = spt.T[idb].son[0];
                    //spt.PushDown(idb);
                    ans = spt.T[idb].K + spt.T[ida].K + spt.T[idson].sumk;
                }
                printf("%I64d
    ",ans);
                //cout<<ans<<endl;
            }
            else
            {
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                
                if(a==b)
                {
                    int id = spt.Find(a);
                    spt.T[id].K += c;
                    spt.T[id].sumk += c;
                    // 这个节点的值改变了,还是得往上推
                    spt.Splay(id, 0);
                }
                else
                {
                    int ida,idb;
                    idb = spt.Find(b);
                    ida = spt.Find(a);
                    
                    spt.T[ida].K += c;
                    //spt.T[ida].sumk += c;
                    spt.T[idb].K += c;
                    //spt.T[idb].sumk += c;
                    
                    spt.Splay(idb, ida);
                    
                    int idson = spt.T[idb].son[0];
                    
                    if(idson != 0)
                    {
                        spt.T[ idson ].sumk += spt.T[ idson ].size*c;
                        spt.T[ idson ].K += c;
                        Add[idson] += c;// 当全局变量来用
                        spt.Splay(idson, 0);//还得往上推一下吧
                    }
                    
                }
                
            }
        }
        return 0;
    }
  • 相关阅读:
    基于Hadoop的改进Apriori算法
    iOS 访问URL转码
    第一次进入应用图片轮播效果
    购物篮模型&Apriori算法
    Ionicons的使用
    如何在 Eclipse 中使用命令行
    Eclipse输入命令行参数
    CHAR,TCHAR,WCHAR 三者的区别与转换
    函数名、变量前后的_(一个下划线)、__(两个下划线)分别有什么用
    java爬虫简单实现
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/5324580.html
Copyright © 2011-2022 走看看