插入操作,删除操作和置换操作都是单点的,所以不需要lazy标记。这个很简单,都是两次RotateTo,一次Splay操作就搞定。

求最大连续字段和的操作和线段树的题目类似,只需要保存最左边的连续最大字段和,最右边的连续最大字段和,整个子树的连续最大字段和就OK,整个子树的和就OK。

注意PushUp函数的写法就OK

  1. //Problem Specific Function
  2. void PushUp(int x )
  3. {
  4. int ll = sp[x].child[0], rr = sp[x].child[1];
  5. // sz, lsum , rsum , msum, sum
  6. sp[x].sz = 1 + sp[sp[x].child[0]].sz + sp[sp[x].child[1]].sz;
  7. sp[x].sum = sp[x].val + sp[sp[x].child[0]].sum + sp[sp[x].child[1]].sum;
  8. sp[x].lsum = max(sp[ll].lsum, sp[ll].sum + sp[x].val + max(sp[rr].lsum, 0));
  9. sp[x].rsum = max(sp[rr].rsum, sp[rr].sum + sp[x].val + max(sp[ll].rsum , 0));
  10. // 这里类似于线段树的
  11. sp[x].msum = max(max(sp[ll].msum, sp[rr].msum), sp[x].val + max(sp[ll].rsum, 0) + max(sp[rr].lsum, 0));
  12. }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

这个题目的代码

  1. 1:  
  1. 2: #include <cstdio>
  1. 3: #include <iostream>
  1. 4:  
  1. 5: using namespace std;
  1. 6: #define INF 10009
  1. 7: #define MaxL 222222
  1. 8: #define keyTree sp[sp[root].child[1]].child[0]
  1. 9:  
  1. 10: struct SplayTreeNode
  1. 11: {
  1. 12: int parent, child[2]; // parent and child[0] left child[1] right
  1. 13: int sz, val; // sz 表示当前节点为根的子树总节点个数. val表示当前节点的键值。
  1. 14: int sum; // 以x为根节点的子树的所有的和
  1. 15: int lsum; // 以该点为根的子树的左子树最大的连续和 [left, x)
  1. 16: int rsum; // 以该点为根的子树的右子树 最大的连续和 (x, right]
  1. 17: int msum; // 以该点为根的子树中的连续最大字段和
  1. 18: };
  1. 19:  
  1. 20: int num[MaxL];
  1. 21: struct SpalyTree
  1. 22: {
  1. 23: SplayTreeNode sp[MaxL]; // save space
  1. 24: int gc[MaxL]; // Garbage Collection idx
  1. 25: int root; // root idx
  1. 26: int idx; // Forward allocate tree
  1. 27: int idxrev; // garbage allocated nodes used for next allocation priority
  1. 28:  
  1. 29: /*
  1. 30: A B
  1. 31: / \ R(B,RR)-> / \
  1. 32: B C <-R(A,LL) D A
  1. 33: / \ / \
  1. 34: D E E C
  1. 35: */
  1. 36: void Rotate(int x,int f) // f ==0 l rot,1 r rot
  1. 37: {
  1. 38: int y = sp[x].parent;
  1. 39: //PushDown(y);
  1. 40: //PushDown(x);
  1. 41: sp[y].child[!f] = sp[x].child[f];
  1. 42: sp[sp[x].child[f]].parent = y;
  1. 43: sp[x].parent = sp[y].parent;
  1. 44: if(sp[x].parent)
  1. 45: sp[sp[y].parent].child[ sp[sp[y].parent].child[1] == y]= x;
  1. 46: sp[x].child[f] = y;
  1. 47: sp[y].parent = x;
  1. 48: PushUp(y);
  1. 49: }
  1. 50:  
  1. 51: void Splay(int x, int goal)
  1. 52: {
  1. 53: //PushDown(x);
  1. 54: while(sp[x].parent != goal)
  1. 55: {
  1. 56: if(sp[sp[x].parent].parent == goal)
  1. 57: Rotate(x, sp[sp[x].parent].child[0] == x);
  1. 58: else
  1. 59: {
  1. 60: int y = sp[x].parent, z = sp[y].parent;
  1. 61: int f = sp[z].child[0] == y;
  1. 62: if(sp[y].child[f] == x)
  1. 63: Rotate(x,!f), Rotate(x,f);
  1. 64: else
  1. 65: Rotate(y,f), Rotate(x,f);
  1. 66:  
  1. 67: }
  1. 68: }
  1. 69: PushUp(x);
  1. 70: if(goal == 0) root = x;
  1. 71: }
  1. 72: // 把第k个的数转到goal下边,一般用来调整区间
  1. 73: int RotateTo(int k, int goal)
  1. 74: {
  1. 75: int x = root;
  1. 76: //PushDown(x);
  1. 77: while(sp[sp[x].child[0]].sz !=k)
  1. 78: {
  1. 79: if( k< sp [ sp[x].child[0] ].sz)
  1. 80: x = sp[x].child[0];
  1. 81: else
  1. 82: {
  1. 83: k -= sp[sp[x].child[0]].sz +1;
  1. 84: x = sp[x].child[1];
  1. 85: }
  1. 86: // PushDown(x);
  1. 87: }
  1. 88: // cout<<"Rotate "<<x<<" goal "<<goal<<endl;
  1. 89: Splay(x, goal);
  1. 90: return x;
  1. 91: }
  1. 92:  
  1. 93: void NewNode(int &x, int c)
  1. 94: {
  1. 95: if( idxrev) x = gc[--idxrev];
  1. 96: else x = ++idx;
  1. 97: sp[x].child[1] = 0, sp[x].child[0] = 0, sp[x].parent = 0;
  1. 98: sp[x].sz = 1;
  1. 99: sp[x].val = sp[x].sum = sp[x].lsum = sp[x].rsum = sp[x].msum = c;
  1. 100: //sp[x].lazy = 0;
  1. 101: }
  1. 102:  
  1. 103: //把以x为祖先结点(x 也算)删掉放进内存池,回收内存
  1. 104: void eraseSubTree(int x)
  1. 105: {
  1. 106: int father = sp[x].parent;
  1. 107: int head = idxrev , tail = idxrev;
  1. 108: for (gc[tail++] = x ; head < tail ; head ++)
  1. 109: {
  1. 110: idxrev++;
  1. 111: if( sp[gc[head]].child[0]) gc[tail++] = sp[gc[head]].child[0];
  1. 112: if( sp[gc[head]].child[1]) gc[tail++] = sp[gc[head]].child[1];
  1. 113: }
  1. 114: sp[father].child[ sp[father].child[1] == x] = 0;
  1. 115: PushUp(father);
  1. 116: }
  1. 117:  
  1. 118:  
  1. 119: void makeTree(int &x, int l, int r, int parent)
  1. 120: {
  1. 121: if(l > r) return ;
  1. 122: int m = (l+r)>>1;
  1. 123: NewNode(x,num[m]);
  1. 124: makeTree(sp[x].child[0], l, m-1, x);
  1. 125: makeTree(sp[x].child[1], m+1, r, x);
  1. 126: sp[x].parent = parent;
  1. 127: PushUp(x);
  1. 128: }
  1. 129: void Init(int n)
  1. 130: {
  1. 131: idx = idxrev = 0;
  1. 132: root = 0;
  1. 133: sp[0].child[0] = sp[0].child[1] = sp[0].parent = 0;
  1. 134: sp[0].sz = sp[0].sum = 0;
  1. 135: sp[0].val = sp[0].lsum = sp[0].rsum = sp[0].msum = -INF;
  1. 136: NewNode(root, -INF);
  1. 137: NewNode(sp[root].child[1], -INF);
  1. 138: sp[idx].parent = root;
  1. 139: sp[root].sz = 2;
  1. 140: makeTree( sp [sp[root].child[1] ].child[0] , 1, n, sp[root].child[1]);
  1. 141: PushUp(sp[root].child[1]);
  1. 142: PushUp(root);
  1. 143: }
  1. 144:  
  1. 145: void Travel(int x)
  1. 146: {
  1. 147: if(x)
  1. 148: {
  1. 149: Travel( sp[x].child[0]);
  1. 150: printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,val = %2d sum = %2d\n",x, sp[x].child[0],sp[x].child[1],sp[x].parent,sp[x].sz,sp[x].val, sp[x].sum);
  1. 151: Travel( sp[x].child[1]);
  1. 152: }
  1. 153: }
  1. 154:  
  1. 155: //Problem Specific Function
  1. 156: void PushUp(int x )
  1. 157: {
  1. 158: int ll = sp[x].child[0], rr = sp[x].child[1];
  1. 159: // sz, lsum , rsum , msum, sum
  1. 160: sp[x].sz = 1 + sp[sp[x].child[0]].sz + sp[sp[x].child[1]].sz;
  1. 161: sp[x].sum = sp[x].val + sp[sp[x].child[0]].sum + sp[sp[x].child[1]].sum;
  1. 162: sp[x].lsum = max(sp[ll].lsum, sp[ll].sum + sp[x].val + max(sp[rr].lsum, 0));
  1. 163: sp[x].rsum = max(sp[rr].rsum, sp[rr].sum + sp[x].val + max(sp[ll].rsum , 0));
  1. 164: // 这里类似于线段树的
  1. 165: sp[x].msum = max(max(sp[ll].msum, sp[rr].msum), sp[x].val + max(sp[ll].rsum, 0) + max(sp[rr].lsum, 0));
  1. 166: }
  1. 167:  
  1. 168: void Insert(int pos, int m)
  1. 169: {
  1. 170: RotateTo(pos - 1, 0);
  1. 171: RotateTo(pos, root);
  1. 172: int p = 0;
  1. 173: NewNode(p, m);
  1. 174: keyTree = p;
  1. 175: sp[p].parent = sp[root].child[1];
  1. 176: Splay(p,0);
  1. 177: }
  1. 178:  
  1. 179: void Delete(int pos)
  1. 180: {
  1. 181: RotateTo(pos-1, 0);
  1. 182: RotateTo(pos+1, root);
  1. 183: eraseSubTree(keyTree);
  1. 184: Splay(sp[root].child[1], 0);
  1. 185: }
  1. 186:  
  1. 187: void Replace(int pos, int m)
  1. 188: {
  1. 189: RotateTo(pos-1, 0);
  1. 190: RotateTo(pos+1, root);
  1. 191: int x = keyTree;
  1. 192: sp[x].val = sp[x].sum = sp[x].lsum = sp[x].rsum = sp[x].msum = m;
  1. 193: Splay(keyTree,0);
  1. 194: }
  1. 195:  
  1. 196: int Query(int l, int r)
  1. 197: {
  1. 198: RotateTo(l -1, 0);
  1. 199: RotateTo(r+1, root);
  1. 200:  
  1. 201: int ret = sp[keyTree].msum;
  1. 202: Splay(keyTree,0);
  1. 203: return ret;
  1. 204: }
  1. 205: } spt;
  1. 206:  
  1. 207:  
  1. 208: int main()
  1. 209: {
  1. 210: // freopen("1.txt","r",stdin);
  1. 211: int n;
  1. 212: while(scanf("%d",&n)!=EOF)
  1. 213: {
  1. 214: for(int i=1; i<=n; i++)
  1. 215: scanf("%d",&num[i]);
  1. 216: spt.Init(n);
  1. 217: int q;
  1. 218: scanf("%d", &q);
  1. 219: while(q--)
  1. 220: {
  1. 221: char op[2];
  1. 222: scanf("%s",op);
  1. 223: int pos,m;
  1. 224: if(op[0]=='I')
  1. 225: {
  1. 226: n++;
  1. 227: scanf("%d%d",&pos, &m);
  1. 228: spt.Insert(pos,m);
  1. 229: }
  1. 230: else if(op[0]=='D')
  1. 231: {
  1. 232: n--;
  1. 233: // scanf_(pos);
  1. 234: scanf("%d", & pos);
  1. 235: spt.Delete(pos);
  1. 236: }
  1. 237: else if(op[0]=='R')
  1. 238: {
  1. 239: scanf("%d%d",&pos, &m);
  1. 240: spt.Replace(pos,m);
  1. 241: }
  1. 242: else if(op[0]=='Q')
  1. 243: {
  1. 244: scanf("%d%d", &pos, &m);
  1. 245: printf("%d\n", spt.Query(pos,m));
  1. 246: }
  1. 247: }
  1. 248: }
  1. 249: return 0;
  1. 250: }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

SPOJ 4487 Splay 基本操作的更多相关文章

  1. spoj 4487. Can you answer these queries VI (gss6) splay 常数优化

    4487. Can you answer these queries VI Problem code: GSS6 Given a sequence A of N (N <= 100000) in ...

  2. SPOJ 4487. Can you answer these queries VI splay

    题目链接:点击打开链接 题意比較明显,不赘述. 删除时能够把i-1转到根,把i+1转到根下 则i点就在 根右子树 的左子树,且仅仅有i这一个 点 #include<stdio.h> #in ...

  3. Splay基本操作

    我们以一道题来引入吧! 传送门 题目说的很清楚,我们的数据结构要支持:插入x数,删除x数,查询数的排名和排名为x的数,求一个数前驱后继. 似乎用啥现有的数据结构都很难做到在O(nlogn)的复杂度中把 ...

  4. 【BZOJ-1552&3506】robotic sort&排序机械臂 Splay

    1552: [Cerc2007]robotic sort Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 806  Solved: 329[Submit][ ...

  5. splay详解(一)

    前言 Spaly是基于二叉查找树实现的, 什么是二叉查找树呢?就是一棵树呗:joy: ,但是这棵树满足性质—一个节点的左孩子一定比它小,右孩子一定比它大 比如说 这就是一棵最基本二叉查找树 对于每次插 ...

  6. splay:优雅的区间暴力!

    万年不更的blog主更新啦!主要是最近实在忙,好不容易才从划水做题的时间中抽出一段时间来写这篇blog 首先声明:这篇blog写的肯定会很基础...因为身为一个蒟蒻深知在茫茫大海中找到一个自己完全能够 ...

  7. POJ3468:A Simple Problem with Integers (线段树||树状数组||Splay解决基本问题的效率对比)

    You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of op ...

  8. Splay&LCT

    Splay && LCT \(\text{Splay}\) 基本操作 1.\(Zig \& Zag\) 其思想是维护中序遍历不变 实现中我们不真的用\(Zig\)或\(Zag\ ...

  9. 【学术篇】NOIP2017 d2t3 列队phalanx splay做法

    我可去他的吧.... ==============先胡扯些什么的分割线================== 一道NOIP题我调了一晚上...(其实是因为昨晚没有找到调试的好方法来的说...) 曾经我以 ...

随机推荐

  1. dede只调用当天发布的文档

    dede只调用当天发布的文档 dede文章的调用 我需要织梦的模板分别调用,一天内发布的文章,三天内发布的文章,和七天内发布的文章,请问是代码是怎么写的,如何调用,如图所示. 点一天内,显示最近24的 ...

  2. IP地址,子网掩码,默认网关,路由,形象生动阐述

    自己的Linux虚拟机已经分配了固定的IP地址(使用无线路由,用的是192.168.1.XX网段),公司的无线网络分配的IP地址是(10.51.174.XX网段) 所以当自己的电脑拿到公司,还想使用桥 ...

  3. [改善Java代码]使用package-info类为包服务

    建议50: 使用package-info类为包服务 Java中有一个特殊的类:package-info类,它是专门为本包服务的,为什么说它特殊呢?主要体现在3个方面: (1)它不能随便被创建 在一般的 ...

  4. [改善Java代码]不要让类型默默转换

    建议23:不要让类型默默转换 public class Client { // 光速是30万公里/秒,常量 public static final int LIGHT_SPEED = 30 * 100 ...

  5. 【KMP原理】【整理回顾】

    今儿套KMP模板做了个题,敏敏找我讲next[]数组的时候把我问懵了.具体原理都记不清了光靠模板凑得了一时凑不了一世啊,所以再捋一捋顺一顺,这次印象要深刻一点了: KMP与暴力匹配的优化区别就不再提了 ...

  6. 【Knockout】四、绑定上下文

    Binding context binding context是一个保存数据的对象,你可以在你的绑定中引用它.当应用绑定的时候,knockout自动创建和管理binding context的继承关系. ...

  7. C# 计算文件的 Hash 值

    /// <summary> /// 提供用于计算指定文件哈希值的方法 /// <example>例如计算文件的MD5值: /// <code> /// String ...

  8. 通过读取配置文件App.config来获取数据库连接字符串

    有两种方式://通过读取配置文件来获取连接字符串 第一种方式: App.config 文件的格式: <?xml version="1.0" encoding="ut ...

  9. jQuery中ajax应用

    一:Ajax介绍 1.ajax的定义:客服端js所发起的http请求的代号,无刷新的数据更新. 2.ajax原理: 运用XHTML+CSS来表达信息,运用javascript操作DOM(Documen ...

  10. orcale 循环插入 测试数据

    以前开发一直用的是sql server   定义临时变量 循环插入数据到表中已经成为一种固定的模式,本来想orcale应该也一样吧 都是数据库.. 结果被现实无情的打击到了.在网上找办法,求大神 最后 ...