SPOJ 4487 Splay 基本操作

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

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

注意PushUp函数的写法就OK

//Problem Specific Function
void PushUp(int x )
{
int ll = sp[x].child[0], rr = sp[x].child[1];
// sz, lsum , rsum , msum, sum
sp[x].sz = 1 + sp[sp[x].child[0]].sz + sp[sp[x].child[1]].sz;
sp[x].sum = sp[x].val + sp[sp[x].child[0]].sum + sp[sp[x].child[1]].sum;
sp[x].lsum = max(sp[ll].lsum, sp[ll].sum + sp[x].val + max(sp[rr].lsum, 0));
sp[x].rsum = max(sp[rr].rsum, sp[rr].sum + sp[x].val + max(sp[ll].rsum , 0));
// 这里类似于线段树的
sp[x].msum = max(max(sp[ll].msum, sp[rr].msum), sp[x].val + max(sp[ll].rsum, 0) + max(sp[rr].lsum, 0));
}

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

时间: 2024-11-03 03:47:48

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

SPOJ 4487. Can you answer these queries VI splay

题目链接:点击打开链接 题意比较明显,不赘述. 删除时可以把i-1转到根,把i+1转到根下 则i点就在 根右子树 的左子树,且只有i这一个 点 #include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> using namespace std; #define N 300500 #define inf 10000000 #define L(x) tree[x].ch[

spoj 4487. Can you answer these queries VI splay 常数优化

4487. Can you answer these queries VI Problem code: GSS6 Given a sequence A of N (N <= 100000) integers, you have to apply Q (Q <= 100000) operations: Insert, delete, replace an element, find the maximum contiguous(non empty) sum in a given interval

SPOJ GSS系列 最大子段和 线段树+树链剖分+splay 1043 1557 1716 2713 2916 4487 6779

最大子段和的各种形式 题解内附每道题的 题意 题目链接 思路 SPOJ 1043 GSS1 静态区间求个最大子段和, 题解 SPOJ 1577 GSS2 和1一样,区别是若区间内存在相同的元素,则该元素只计算一次. 离线一下然后使劲跑.. 题解 SPOJ 1716 GSS3 和1一样,就是要支持单点修改 题解 SPOJ 2713 GSS4 ==普通线段树,感觉和这系列关系不大. 题解 SPOJ 2916 GSS5 题意有点怪,,跟3差不多,就是稍加强了点询问 题解 SPOJ 4487 GSS6

【BZOJ-1552&amp;3506】robotic sort&amp;排序机械臂 Splay

1552: [Cerc2007]robotic sort Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 806  Solved: 329[Submit][Status][Discuss] Description Input 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000.第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号. Output 输出共一行,N个用空格隔开的正整数P1,P2,P3…Pn,Pi表示第i次操作

splay:优雅的区间暴力!

万年不更的blog主更新啦!主要是最近实在忙,好不容易才从划水做题的时间中抽出一段时间来写这篇blog 首先声明:这篇blog写的肯定会很基础...因为身为一个蒟蒻深知在茫茫大海中找到一个自己完全能够看懂的blog有多么的难..(说多了都是泪.)所以当然希望所有初学者都能看懂这篇博文啦~ 说实话在学这个算法之前有跟强大的巨神zxyer学过treap和fhq_treap,所以对平衡树有一定的了解.当然都是理论阶段,虽然都打过一两题,但是忘得快..所以几乎等于没打. 认真重学了一遍平衡树(尤其是sp

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

我可去他的吧.... ==============先胡扯些什么的分割线================== 一道NOIP题我调了一晚上...(其实是因为昨晚没有找到调试的好方法来的说...) 曾经我以为我写完了然后全WA 0分 发现 2 1 2 1 1 1 1 这组数据能把我卡掉(我都不知道怎么过样例的)... 然后就开始调就精神崩溃就放弃治疗就划水就过去了一下午和一晚上... 今天我立(砾)志要完成这道题. 上luogu打卡 两个号(不要问我为啥两个号)分别: 然后说我调不出WA的题我就很绝望

洛谷P2286宠物收养场

1 #include<cstdio> 2 #define abs(a,b) (a>b?a-b:b-a) 3 #define MOD 1000000 4 #define MXN 450000+5 5 int read(){ 6 int x=0,w=1; 7 char c=getchar(); 8 while(c<'0'||c>'9'){ 9 if(c=='-') w=-1; 10 c=getchar(); 11 } 12 while(c>='0'&&c&l

SPOJ GSS6 4487. Can you answer these queries VI (SPLAY)

题目大意: 四个操作: I X Y 在x位置插入y D x 删除x位置的数 R x y 用y替换x位置上的数字 Q x y 求出[x,y]上的最大子序列的和. 思路分析: 对于动态维护序列肯定是splay了. 现在就考虑以下几个问题. 之前我们知道线段树处理连续的子序列的和是用区间合并的.那splay上怎么做. 考虑边界,如儿子为 0 或者是冗余节点怎么办? 初始化的时候将值赋成什么. 仔细考虑这些就能减少代码量. 注意replace的时候,要去找到然后直接修改,如果先旋转的话就会造成超时. #

SPOJ GSS6 Can you answer these queries VI ——Splay

[题目分析] 增加了插入和删除. 直接用Splay维护就好辣! 写了一个晚上,(码力不精),最后发现更新写挂了 [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include