【HAOI2008】排名系统

Description

设计一种数据结构,支持给指定点插入元素并覆盖先前的元素、查询某一点的排名、输出从任意排名之后的10名。

Solution

采用Splay实现

关于读入的字符串,我们可以哈希然后将哈希值丢到map里,这样就可以给每一个字符串一个编号,方便在Splay上操作。

关于插入和删除以及查询操作,都是Splay的基本操作,在此不再赘述。

关于输出答案,我们这样思考:根据BST的性质,当前点的右子树的值一定大于当前点,左子树的值一定小于当前点,也就意味着我们对这棵树进行一次中序遍历就可以得到一个有序序列。那么我们输出答案也是如此,先在右子树中递归输出,在输出当前节点,再进入左子树,同时开一个计数器记录当前输出了多少答案即可。

为了维护Splay的随机性,我们每执行200次操作就随机一个节点并将它延伸到树根。

Code

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef unsigned long long ull;
  4 const int INF = 2147483647;
  5 const ull mod = 212370440130137957ll;
  6 inline int read() {
  7     int ret = 0, op = 1;
  8     char c = getchar();
  9     while (!isdigit(c)) {
 10         if (c == '-') op = -1; 
 11         c = getchar();
 12     }
 13     while (isdigit(c)) {
 14         ret = ret * 10 + c - '0';
 15         c = getchar();
 16     }
 17     return ret * op;
 18 }
 19 inline ull rethash(char *aa) {
 20     ull ret = 0;
 21     int l = strlen(aa + 1);
 22     for (register int i = 1; i <= l; ++i)
 23         ret = (ret * 131 + aa[i]) % mod;
 24     return ret;
 25 }
 26 inline int retnum(char *aa) {
 27     int ret = 0;
 28     int l = strlen(aa + 1);
 29     for (register int i = 1; i <= l; ++i) 
 30         ret = ret * 10 + aa[i] - '0';
 31     return ret;
 32 }
 33 map <ull, int> hash;
 34 int n, root, tot, len[250010];
 35 struct Splay {
 36     int fa, sum, ch[2], val;
 37 } a[250010];
 38 char in[20], name[250010][20];
 39 void update(int now) {
 40     a[now].sum = a[a[now].ch[0]].sum + a[a[now].ch[1]].sum + 1;
 41 } 
 42 void connect(int x, int fa, int op) {
 43     a[x].fa = fa;
 44     a[fa].ch[op] = x;
 45 }
 46 void rotate(int x) {
 47     int y = a[x].fa;
 48     int z = a[y].fa;
 49     int xson = a[y].ch[1] == x;
 50     int yson = a[z].ch[1] == y;
 51     int B = a[x].ch[xson ^ 1];
 52     connect(B, y, xson); connect(y, x, xson ^ 1); connect(x, z, yson);
 53     update(y); update(x);
 54 }
 55 void splay(int from, int to) {
 56     while (a[from].fa != to) {
 57         int y = a[from].fa;
 58         int z = a[y].fa;
 59         if (z != to) (a[y].ch[0] == from) ^ (a[z].ch[0] == y) ? rotate(from) : rotate(y);
 60         rotate(from);
 61     }
 62     if (to == 0) root = from;
 63 }
 64 void insert(int val, int x) {
 65     int now = root, fa = 0;
 66     while (1) {
 67         if (!now) {
 68             a[x].val = val;
 69             a[x].fa = fa;
 70             a[x].sum = 1;
 71             a[fa].ch[val > a[fa].val] = x;
 72             splay(x, 0);
 73             return ;
 74         }
 75         fa = now;
 76         now = a[now].ch[val > a[now].val];
 77     }
 78 }
 79 int query(int x) {
 80     int now = root;
 81     while (1) {
 82         if (x <= a[a[now].ch[0]].sum) now = a[now].ch[0];
 83         else {
 84             x -= a[a[now].ch[0]].sum + 1;
 85             if (!x) return now;
 86             now = a[now].ch[1];
 87         }
 88     }
 89 }
 90 void del(int x) {
 91     splay(x, 0);
 92     int size = a[a[root].ch[0]].sum;
 93     int l = query(size);
 94     int r = query(size + 2);
 95     splay(l, 0); splay(r, l);
 96     a[r].ch[0] = 0;
 97     update(r); update(l);
 98     a[x].fa = a[x].val = a[x].sum = 0;
 99 }
100 void print(int now, int &sum) {
101     if (sum >= 10) return ;
102     if (a[now].ch[1]) print(a[now].ch[1], sum);
103     if (sum >= 10) return ;
104     if (now > 2) {
105         sum++;
106         for (register int i = 1; i < len[now]; ++i)
107             putchar(name[now][i]);
108         putchar(' ');
109     }
110     if (a[now].ch[0]) print(a[now].ch[0], sum);
111 }
112 int main() {
113     srand(20040312);
114     n = read();
115     insert(-INF, ++tot); insert(INF, ++tot);
116     for (register int i = 1; i <= n; ++i) {
117         scanf("%s", in);
118         if (in[0] == '+') {
119             ull ret = rethash(in); int x = read();
120             if (hash[ret]) {
121                 del(hash[ret]);
122                 insert(x, hash[ret]);
123             }
124             else {
125                 insert(x, hash[ret] = ++tot);
126                 for (register int i = 1; i < strlen(in); ++i) name[tot][i] = in[i];
127                 len[tot] = strlen(in);
128             }
129         }
130         else if (isdigit(in[1])) {
131             int x = retnum(in);
132             int l = query(tot - x + 1);
133             splay(l, 0);
134             int sum = 0;
135             print(a[l].ch[0], sum);
136             puts("");
137         }
138         else {
139             ull ret = rethash(in);
140             splay(hash[ret], 0);
141             printf("%d\n", a[a[root].ch[1]].sum);
142         }
143         if (i % 200 == 0) splay(rand() % tot + 1, 0);
144     }
145     return 0;
146 }
AC Code

 

转载于:https://www.cnblogs.com/shl-blog/p/11278875.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值