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\n",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;
}
时间: 2024-10-12 11:02:26

splay tree成段更新,成段查询poj3466的相关文章

Wikioi 1082线段树成段更新成段查询

这题从昨晚搞到现在敲了又改好久,刚开始是update中错了,然后找到了.但是还错,然后因为题目没有数据的范围提示,所以弄了好久都不知道哪错了,最后看评论才知道是超int了,改了之后还有错,然后才发现虽然改成long long了,但是输出的时候没改,哈哈-- #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <deque> #in

POJ 2777 Count Color (线段树成段更新+二进制思维)

题目链接:http://poj.org/problem?id=2777 题意是有L个单位长的画板,T种颜色,O个操作.画板初始化为颜色1.操作C讲l到r单位之间的颜色变为c,操作P查询l到r单位之间的颜色有几种. 很明显的线段树成段更新,但是查询却不好弄.经过提醒,发现颜色的种类最多不超过30种,所以我们用二进制的思维解决这个问题,颜色1可以用二进制的1表示,同理,颜色2用二进制的10表示,3用100,....假设有一个区间有颜色2和颜色3,那么区间的值为二进制的110(十进制为6).那我们就把

POJ2155 Matrix 【二维树状数组】+【段更新点查询】

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 17766   Accepted: 6674 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

HDU 5274 Dylans loves tree(LCA+dfs时间戳+成段更新 OR 树链剖分+单点更新)

Problem Description Dylans is given a tree with N nodes. All nodes have a value A[i].Nodes on tree is numbered by 1∼N. Then he is given Q questions like that: ①0 x y:change node x′s value to y ②1 x y:For all the value in the path from x to y,do they

[HDOJ4027]Can you answer these queries?(线段树,特殊成段更新,成段查询)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4027 RT,该题要求每次更新是更新所有节点,分别求平方根,查询是求和.昨晚思前想后找有没有一个数学上的开平方的和等于和的开平方之类的规律.但是想了想发现这不就是小的时候,如果你这么想那老师就会骂死你的那个- -! 所以显然这个题是无法按套路成段更新了,懒惰标记也是没有用了,我们应该去按照区间更新每一个节点.结果TLE了一发,这说明这题不是这么搞,一定还有规律的.注意到题目给数据规模是2^63以及题目

HDU1698 Just a Hook 【线段树】+【成段更新】+【lazy标记】

Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 15889    Accepted Submission(s): 7897 Problem Description In the game of DotA, Pudge's meat hook is actually the most horrible thing

ACM: Copying Data 线段树-成段更新-解题报告

Copying Data Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Description We often have to copy large volumes of information. Such operation can take up many computer resources. Therefore, in this problem you are advised to come

Hdu 3397 Sequence operation(线段树多操作,Lazy思想,成段更新)

Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6397    Accepted Submission(s): 1899 Problem Description lxhgww got a sequence contains n characters which are all '0's or '1

Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)

题目链接:http://codeforces.com/problemset/problem/242/E 给你n个数,m个操作,操作1是查询l到r之间的和,操作2是将l到r之间的每个数xor与x. 这题是线段树成段更新,但是不能直接更新,不然只能一个数一个数更新.这样只能把每个数存到一个数组中,长度大概是20吧,然后模拟二进制的位操作.仔细一点就行了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cmath>