zoukankan      html  css  js  c++  java
  • [HNOI2004]宠物收养场

    嘟嘟嘟


    看完题,思路一秒就出来了:建两棵平衡树,分别维护宠物和领养者。然后就是正常的插入,找前驱后继,删除操作了。
    然后旁边的lba巨佬说只用建一棵就行,如果宠物多了就维护宠物,否则维护领养者。
    总而言之这就是一道板儿题。


    然而我刚学(splay)啊!
    于是一上午就这么过去了。
    旋转,插入,找前驱后继这些操作就不说了,可以看我昨天的博客。主要是删除操作困扰了我半天。
    啊不对,找前驱后继得说一下。
    拿找前驱为例。众所周知,我们先找(x),然后把他旋到根,这样的话前驱就是先走一步左儿子,然后右儿子一直走下去。
    但是这道题(x)可能不在平衡树里。于是我就懵了,想了半天都不知道怎么改进,最后还是拿(bst)的找法去写的,然而写完后就发现删除操作写不了了。因为删除我需要(x)的前驱和后继的节点编号,但是按(bst)的写法只能返回值,而没有节点编号。
    因此最后我还不得不回来看(lba)的代码。然而看了半天我也没看出来他怎么处理这一点的,问他他说没考虑到这一点,但这样的话样例怎么解释呀!在各种磨叽后我终于看到了百行代码中的一条不寻常的特判:就是在找前驱的时候,旋转完如果根的值比(x)小就直接返回!然后我想了想,发现奥秘在这里:查找的时候如果(x)不存在,找到的是离(x)最近的数(y),然后把他旋了上去,但不知道比(x)大还是比(x)小。这样找前驱的时候,如果根节点(就是(y))比(x)小,说明(y)(x)小,直接返回(y)。后继同理。
    嗯,就是这样。


    然后叨叨一下删除。
    删除权值为(x)的节点,先找(x)的前驱(a)和后继(b),然后把(a)旋到根上,再把(b)旋到(a)的右儿子上。这样(x)就一定是(b)的左儿子,而且(b)的左子树只有(x)。所以如果(x)有多个,就(cnt--),否则把(b)的左子树变为(0)
    代码

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define rg register
    typedef long long ll;
    typedef double db;
    const int INF = 2147483647;
    const db eps = 1e-8;
    const int maxn = 8e4 + 5;
    const int mod = 1000000;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    
    int n, tot = 0;
    ll ans = 0;
    
    struct Tree
    {
      int ch[2], fa;
      int cnt, siz; ll val;
    }t[maxn];
    int root, ncnt = 0;
    
    void pushup(int now)
    {
      t[now].siz = t[t[now].ch[0]].siz + t[t[now].ch[1]].siz + t[now].cnt;
    }
    void rotate(int x)
    {
      int y = t[x].fa, z = t[y].fa, k = (t[y].ch[1] == x);
      t[z].ch[t[z].ch[1] == y] = x; t[x].fa = z;
      t[y].ch[k] = t[x].ch[k ^ 1]; t[t[x].ch[k ^ 1]].fa = y;
      t[x].ch[k ^ 1] = y; t[y].fa = x;
      pushup(x); pushup(y);
    }
    void splay(int x, int s)
    {
      while(t[x].fa != s)
        {
          int y = t[x].fa, z = t[y].fa;
          if(z != s)
    	{
    	  if((t[z].ch[0] == y) ^ (t[y].ch[0] == x)) rotate(x);
    	  else rotate(y);
    	}
          rotate(x);
        }
      if(!s) root = x;
    }
    void insert(int x)
    {
      int now = root, f = 0;
      while(now && t[now].val != x) f = now, now = t[now].ch[x > t[now].val];
      if(now) t[now].cnt++;
      else
        {
          now = ++ncnt;
          t[now].ch[0] = t[now].ch[1] = 0;
          if(f) t[f].ch[x > t[f].val] = now;
          t[now].fa = f;
          t[now].cnt = t[now].siz = 1;
          t[now].val = x;
        }
      splay(now, 0);
    }
    void find(int x)
    {
      int now = root;
      if(!now) return;
      while(t[now].ch[x > t[now].val] && t[now].val != x) now = t[now].ch[x > t[now].val];
      splay(now, 0);
    }
    int pre(int x)
    {
      find(x);  
      if(t[root].val < x) return root;
      int now = t[root].ch[0];
      while(t[now].ch[1]) now = t[now].ch[1];
      return now;
    }
    int nxt(int x)
    {
      find(x);
      if(t[root].val > x) return root;
      int now = t[root].ch[1];
      while(t[now].ch[0]) now = t[now].ch[0];
      return now;
    }
    void del(int x)
    {
      int a = pre(x), b = nxt(x);
      splay(a, 0); splay(b, a);
      int k = t[b].ch[0];
      if(t[k].cnt > 1) t[k].cnt--;
      else t[b].ch[0] = 0;
    }
    
    void _Debug(int now)
    {
      if(!now) return;
      printf("()()%d %lld zuo:%lld you:%lld
    ", now, t[now].val, t[t[now].ch[0]].val, t[t[now].ch[1]].val);
      _Debug(t[now].ch[0]); _Debug(t[now].ch[1]);
    }
    
    int main()
    {
      n = read();
      insert(INF); insert(-INF);
      for(int i = 1; i <= n; ++i)
        {
          int op = read(); ll x = read();
          if(!op)
    	{
    	  if(tot >= 0) insert(x);
    	  else
    	    {
    	      ll a = t[pre(x)].val, b = t[nxt(x)].val;
    	      if(x - a <= b - x) ans = (ans + x - a) % mod, del(a);
    	      else ans = (ans + b - x) % mod, del(b);
    	    }
    	  tot++;
    	}
          else
    	{
    	  if(tot <= 0) insert(x);
    	  else
    	    {
    	      //_Debug(root);
    	      ll a = t[pre(x)].val, b = t[nxt(x)].val;
    	      //puts("------");
    	      //_Debug(root);
    	      if(x - a <= b - x) ans = (ans + x - a) % mod, del(a);
    	      else ans = (ans + b - x) % mod, del(b);
    	    }
    	  tot--;
    	}
        }
      write(ans), enter;
      return 0;
    }
    
  • 相关阅读:
    1.4.2.3. SETUP(Core Data 应用程序实践指南)
    1.4.2.2. PATHS(Core Data 应用程序实践指南)
    1.4.2.1. FILES(Core Data 应用程序实践指南)
    1.4.2. 实现 Core Data Helper 类(Core Data 应用程序实践指南)
    1.4.1. Core Data Helper 简介(Core Data 应用程序实践指南)
    1.4. 为现有的应用程序添加 Core Data 支持(Core Data 应用程序实践指南)
    1.3.2. App Icon 和 Launch Image(Core Data 应用程序实践指南)
    1.3.1. 新建Xcode项目并设置故事板(Core Data 应用程序实践指南)
    php验证邮箱是否合法
    如何使js函数异步执行
  • 原文地址:https://www.cnblogs.com/mrclr/p/10048835.html
Copyright © 2011-2022 走看看