大二上的时候。写过一个AVL的操作演示,今天一看Splay。发现和AVL事实上一样,加上线段树的基础,懒惰标记什么都知道。学起来轻松很多哦

我參考的模板来自这里  http://blog.csdn.net/u013480600/article/list/2

里面有大量的ch[r][0] ch[r][1]等 我建议用宏定义代替,写的时候方括号少打了非常多,等做的题多得时候,我再把自己使用的模板发来

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; /*===============================
Splay树模板
1、tot1,tot2都是从1開始
2、
================================*/ #define key_value ch[ch[root][1]][0]
#define ls(r) ch[r][0]
#define rs(r) ch[r][1]
#define ll long long
#define repe(i,s,e) for(int i=s;i<=e;i++)
#define rep(i,s,e) for(int i=s;i<e;i++) const int MAXN=100000 +10;
int pre[MAXN],ch[MAXN][2],sz[MAXN],root,tot1;
// 父节点、左右孩子(0为左,同一时候0为左旋)、子树规模、根节点、结点数量
int key[MAXN];//结点的值
int add[MAXN];
ll sum[MAXN];//sum[i]=v 以i为root的树的和,
int s[MAXN],tot2;/////??? ? ? ? //内存池、内存池容量(这题用不到。假设有删除操作。内存不够能够这样
//s中存的是被回收的内存,从后面能够看到,tot2不为0的时候优先使用s[tot2]=x中的
//pre[x],ch[x],size[x]等,
//否则就使用tot1++之后产生的数x的相应位置
int a[MAXN];//初始时的数组,建树时用
int n,q; void newnode(int &r,int father, int k)//r必须是&
{
if(tot2)r=s[tot2--];//取得时候tot2--,存++tot2
else r=++tot1;
pre[r]=father;
sz[r]=1;
key[r]=k;
add[r]=sum[r]=0;
ch[r][0]=ch[r][1]=0;
} void updateadd(int r, int av)
{
if(!r)return;//? ?
add[r]+=av;
key[r]+=av;
sum[r]+=(ll)av*sz[r];
}
//通过孩子结点更新父亲结点
void pushup(int r)
{
sz[r]=sz[ls(r)]+sz[rs(r)]+1;
sum[r]=sum[ls(r)]+sum[rs(r)]+key[r];
}
//将延迟标记更新到孩子结点
void pushdown(int r)
{
if(add[r])
{
updateadd(ls(r),add[r]);
updateadd(rs(r),add[r]);
add[r]=0;
}
} //建树区间[l,r]。先建立中间结点,再建两端。
//注意和线段树的差别
void build(int &x, int l, int r, int father)
{
if(l>r)return;
int mid=(l+r)/2;
newnode(x, father, a[mid]);
build(ch[x][0], l, mid-1, x);
build(ch[x][1], mid+1, r, x);
pushup(x);
}
//初始化。前后各加一个king结点
void Init()
{
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
root=tot1=tot2=0;
ls(root)=rs(root)=pre[root]=sz[root]=add[root]=sum[root]=key[root]=0;
newnode(root, 0, -1);//root'sfatheris -1
newnode(rs(root),root,-1);//头尾各插入一个空
build(key_value, 1, n, rs(root));
pushup(rs(root));
pushup(root);
}
//旋转,0为左旋。1为右旋 该部分基本固定
void rota(int x, int kind)
{
int y=pre[x];
pushdown(y);
pushdown(x);//必须先把y的标记向下传递。在传x
ch[y][!kind]=ch[x][kind],pre[ch[x][kind]]=y;
if(pre[y])//??y的父节点不是root
ch[pre[y]][ rs(pre[y])==y ]=x;//仅仅能对这句牛逼的代码说声我屮艸芔茻
pre[x]=pre[y];
ch[x][kind]=y,pre[y]=x;
pushup(y);//维护y结点 x节点的信息不用PushUp吗? 能够证明这里除了x节点维护的信息不正确外,其它全部点信息都正确
//Push_Up(x);//这个能够不写,详见Crash:运用伸展树解决数列维护问题 论文,可是写了也不会多多少时间消耗
} void Splay(int r, int goal)//将r调整到goal以下
{
pushdown(r);// 离开之前把懒惰标记的信息传递
while(pre[r]!=goal)
{
if(pre[pre[r]]==goal)
rota(r, ch[pre[r]][0]==r);//r在左子树。右旋
else
{
int y=pre[r];
int kind=ch[pre[y]][0]==y;
if(ch[y][kind]==r)//之字形旋转
{//y在其父节点的左子树上,r在y的右子树上
//或者y在其父节点的右子树。r在y左子树 rota(r, !kind);
rota(r, kind);
}
else //一字型旋转
{
rota(y, kind);//注意这里是y啊
rota(r, kind);
}
}
}
pushup(r);
if(goal==0)root=r;
} //得到第k个结点编号
int getkth(int r, int k)
{
pushdown(r);
int t=sz[ls(r)]+1;
if(t==k)return r;
if(t>k)return getkth(ls(r),k);//在左子树第k个
else return getkth(rs(r), k-t);//在右子树第k-t个
}
//得到以r为根的第一个结点--最左边的节点编号
int getmin(int r)
{
pushdown(r);
while(ls(r))
{
r=ls(r);
pushdown(r);
}
return r;
}
//得到以r为根的最后一个结点--最右边的编号
int getmax(int r)
{
pushdown(r);
while(rs(r))
{
r=rs(r);
pushdown(r);
}
return r;
}
void addv(int l, int r, int d)
{
Splay(getkth(root,l),0);
Splay(getkth(root,r+2),root);
updateadd(key_value, d);
pushup(rs(root));
pushup(root);
} ll Querysum(int l, int r)
{
Splay(getkth(root, l),0);//第l个点到根结点
Splay(getkth(root, r+2), root);//第r+2个点到根结点的右孩子
return sum[key_value];
} int main()
{
//freopen("poj3468.txt","r",stdin);
int q;
while(~scanf("%d%d", &n, &q))
{
Init();
while(q--)
{
char op[30];
int x,y,z;
scanf("%s",op);
if(op[0]=='Q')
{
scanf("%d%d",&x,&y);
printf("%lld\n",Querysum(x,y));
}
else
{
scanf("%d%d%d",&x,&y,&z);
addv(x,y,z);
}
}
}
return 0;
}

poj 3468 Splay 树的更多相关文章

  1. POJ 3468 线段树区间修改查询(Java,c++实现)

    POJ 3468 (Java,c++实现) Java import java.io.*; import java.util.*; public class Main { static int n, m ...

  2. poj 3468(线段树)

    http://poj.org/problem?id=3468 题意:给n个数字,从A1 …………An m次命令,Q是查询,查询a到b的区间和,c是更新,从a到b每个值都增加x.思路:这是一个很明显的线 ...

  3. hdu 1698+poj 3468 (线段树 区间更新)

    http://acm.hdu.edu.cn/showproblem.php?pid=1698 这个题意翻译起来有点猥琐啊,还是和谐一点吧 和涂颜色差不多,区间初始都为1,然后操作都是将x到y改为z,注 ...

  4. poj 3468(线段树+lazy思想)

    题目链接:http://poj.org/problem?id=3468 思路:如果直接去做,每次都更新到叶子节点,那必然会TLE,我们可以采用lazy的思想:没必要每次更新都更新到叶子节点,只要有一个 ...

  5. POJ 3468(树状数组的威力)

    之前说过这是线段树的裸题,但是当看了http://kenby.iteye.com/blog/962159 这篇题解后我简直震惊了,竟然能如此巧妙地转化为用树状数组来处理,附上部分截图(最好还是进入原网 ...

  6. POJ 3468 线段树裸题

    这些天一直在看线段树,因为临近期末,所以看得断断续续,弄得有些知识点没能理解得很透切,但我也知道不能钻牛角尖,所以配合着刷题来加深理解. 然后,这是线段树裸题,而且是最简单的区间增加与查询,我参考了A ...

  7. poj 3468 线段树区间更新/查询

    Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. On ...

  8. POJ 3468 (线段树 区间增减) A Simple Problem with Integers

    这题WA了好久,一直以为是lld和I64d的问题,后来发现是自己的pushdown函数写错了,说到底还是因为自己对线段树理解得不好. 因为是懒惰标记,所以只有在区间分开的时候才会将标记往下传递.更新和 ...

  9. A Simple Problem with Integers poj 3468 多树状数组解决区间修改问题。

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 69589   ...

随机推荐

  1. easyUI样式之easyui-switchbutton

    HTML文件 <tr> <th>是否发送短信:</th> <td> <input id="sendTxt" name=&quo ...

  2. 控制流程完整性:给大家介绍一种“另类”的Javascript反分析技术

    写在前面的话 理解恶意软件的真实代码对恶意软件分析人员来说是非常有优势的,因为这样才能够真正了解恶意软件所要做的事情.但不幸的是,我们并不总是能够得到“真实”的代码,有时恶意软件分析人员可能需要类似反 ...

  3. ZeroMQ使用学习记录(转)

    ZMQ简介 ZMQ(ØMQ.ZeroMQ, 0MQ)看起来像是一套嵌入式的网络链接库,但工作起来更像是一个并发式的框架.它提供的套接字可以在多种协议中传输消息,如线程间.进程间.TCP.广播等.你可以 ...

  4. 项目笔记:导出Excel功能设置导出数据样式

    /** * 导出-新导出 * * @return * @throws IOException */ @OperateLogAnn(type = OperateEnum.EXPORT, hibInter ...

  5. ElasticSearch 监控单个节点详解

    1.介绍 集群健康 就像是光谱的一端——对集群的所有信息进行高度概述. 而 节点统计值 API 则是在另一端.它提供一个让人眼花缭乱的统计数据的数组,包含集群的每一个节点统计值. 节点统计值 提供的统 ...

  6. 修改oracle内存大小

    在默认安装情况下,oracle的内存分配是按系统内存的大小比例分配的,内存比较大的情况下,oracle所占的内存也大,该情况下,我们一般要修改sga值来减少系统中oracle的内存过大问题. 用dba ...

  7. Datatable和实体还有实体集List的差别与转化

    机房收费系统大家想必不是做完.就是已经在手上了,在一開始做的时候就明白规定.我们必须用实体.而不能使Datatable,由于说是Datatable直接面向了数据库,当时不是非常明白,于是也没有再深究, ...

  8. Linux学习笔记 (一)初识linux

    一.什么是Linux Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX工具软件.应用程序和 ...

  9. react-native 常见问题 及 解决方案

    一.报错 Warning:Navigator:isMounted is deprecated. Instead, make sure to clean up subscriptions and pen ...

  10. Android EditText 输入password是否可见

    设置password不可见 etAfter.setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD); 设置password可见 etA ...