平衡树以及序列操作

从今天起,决定:平衡树、序列操作都用双旋非递归splay,主要是各种特判少,弹性大,应用面广,这点比较爽。

splay参考了很多人的写法,最后决定为了优美,用了struct,儿子指针用了一个数组,感觉还很不错,以前的调试问题,由于现在能够一遍写对了,所以也就不存在了。

双旋采取的是自顶向下式的,也是为了常数着想。

下面就是我的NOI05 sequence代码,以后估计不会再写这个题了,刷过几遍了。

再见,我的SBT。

#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <math.h>

#define FOR(i,j,k) for (i = (j); i <= (k); ++i)
#define ROF(i,j,k) for (i = (j); i >= (k); --i)
#define oo 0x3F3F3F3F
inline int max (int i, int j){return i > j ? i : j;}
inline void swap (int *i, int *j){static int t; t = *i, *i = *j, *j = t;}

#define maxn 4000050

struct node
{
  struct node *c[2];
  int key;
  int lms, rms, mss, sum, size;
  int rev, same;
} x[maxn], *null = x, *root, *ptr = x;

struct node *update (struct node *x)
{
  struct node *l = x->c[0], *r = x->c[1];
  x->size = l->size + r->size + 1;
  x->sum  = l->sum  + r->sum  + x->key;
  x->lms  = max (l->lms, l->sum + x->key + max (r->lms, 0));
  x->rms  = max (r->rms, r->sum + x->key + max (l->rms, 0));
  x->mss  = max (max (r->mss, l->mss), max (l->rms, 0) + x->key + max (r->lms, 0));
  return x;
}

void put_rev (struct node *x)
{
  if (x == null) return;
  swap ((int *)&x->c[0] , (int *)&x->c[1]);
  swap (&x->lms         , &x->rms);
  x->rev ^= 1;
}

void put_same (struct node *x, int t)
{
  if (x == null) return;
  x->key  = t;
  x->same = 1;
  x->rev  = 0;
  x->sum  = t * x->size;
  x->lms  = x->rms = x->mss = max (x->sum, t);
}

struct node *push_down (struct node *x)
{
  if (x->same)
    put_same (x->c[0], x->key), put_same (x->c[1], x->key), x->same = 0;
  if (x->rev)
    put_rev (x->c[0]), put_rev (x->c[1]), x->rev = 0;
  return x;
}

void zig (int d)
{
  struct node *t = root->c[d];
  root->c[d]     = null->c[d];
  null->c[d]     = root;
  root           = t;
}

void zigzig (int d)
{
  struct node *t    = root->c[d]->c[d];
  root->c[d]->c[d]  = null->c[d];
  null->c[d]        = root->c[d];
  root->c[d]        = null->c[d]->c[!d];
  null->c[d]->c[!d] = update (root);
  root              = t;
}

void finish (int d)
{
  struct node *p = null->c[d], *q = root->c[!d];
  for (; p != null; )
    {
      p = null->c[d]->c[d];
      null->c[d]->c[d] = q;
      q = update (null->c[d]);
      null->c[d] = p;
    }
  root->c[!d] = q;
}

void splay (int x)
{
  struct node *t; int p;
  for ( ; ; )
    {
      int i = (p = push_down (root)->c[0]->size) < x;
      if (p == x || (t = root->c[i]) == null) break;
      if (i) x -= p + 1;
      int j = (p = push_down (t)->c[0]->size) < x;
      if (p == x || t->c[j] == null) {zig (i); break;}
      if (j) x -= p + 1;
      i != j ? zig (i), zig (j) : zigzig (i);
    }
  finish (0), finish (1), update (root);
}

struct node *build (int l, int r)
{
  if (l > r) return null;
  int m = (l + r) >> 1; struct node *t = x + m;
  t->c[0] = build (l, m - 1);
  t->c[1] = build (m + 1, r);
  return update (t);
}

struct node *interval (int pos, int tot)
{
  splay (pos - 1);
  struct node *bak = root;
  root = bak->c[1];
  splay (tot);
  bak->c[1] = root, root = bak;
  return push_down (root->c[1]->c[0]);
}

int main()
{
  FILE *fin  = fopen ("sequence.in" , "r");
  FILE *fout = fopen ("sequence.out", "w");

  int n, m, i, pos, tot; char cmd[50];

  fscanf (fin, "%d%d", &n, &m);
  *null = (struct node){{null, null}, -oo, -oo, -oo, -oo};
  (++ptr)->key = -oo;
  FOR (i, 1, n)
    fscanf (fin, "%d", &((++ptr)->key));
  (++ptr)->key = -oo;
  root = build (1, n + 2);

  ROF (m, m, 1)
    {
      fscanf (fin, "%s", cmd);
      switch (cmd[2])
        {
        case 'S':
          fscanf (fin, "%d%d", &pos, &tot);
          struct node *t = ptr;
          FOR (i, 1, tot)
            fscanf (fin, "%d", &((++ptr)->key));
          interval (pos + 1, 0);
          root->c[1]->c[0] = build (t - x + 1, ptr - x);
          break;
        case 'L': fscanf (fin, "%d%d", &pos, &tot);  interval (pos, tot); root->c[1]->c[0] = null; break;
        case 'K': fscanf (fin, "%d%d%d", &pos, &tot, &i); put_same (interval (pos, tot), i); break;
        case 'V': fscanf (fin, "%d%d", &pos, &tot); put_rev (interval (pos, tot)); break;
        case 'T': fscanf (fin, "%d%d", &pos, &tot); fprintf (fout, "%d\n", interval (pos, tot)->sum); break;
        case 'X': fprintf (fout, "%d\n", root->mss); break;
        }
      update (root->c[1]), update (root);
    }

  fclose (fin);
  fclose (fout);
  return 0;
}


膜拜宇宙大农统秋哥!



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值