CF916D Jamie and To-do List

怎么题解区没有指针写法啊(恼)

题意:维护带权字符串集合的权值修改,删除元素,求权值意义下的排名。带撤销。强制在线。

Tip:关于为什么是强制在线,这是一道交互题。

思路

注意到不带撤销的话平衡树可以轻松维护,但带撤销就要可持久化。

考虑怎么不写可持久化平衡树,用可持久化动态开点权值线段树维护之。

字符串作下标不太好维护,用 std::map 转换成编号。

建两棵树,$x_i$ 表示编号为 $i$ 的字符串的权值,$y_i$ 表示权值为 $i$ 的字符串的数量。

模拟即可。注意特判询问字符串不存在或权值为 $1$ 的情况。

代码

#include <map>
#include <string>
#include <cstdio>
#define G int m = s + t >> 1
#define D if(u) M(u, -1, 1, 1e9, y[i])
#define S(v) M(a, v - u, 1, 1e5, x[i])
#define I a = F();u = Q(a, a, 1, 1e5, x[i])
#define U(v) x[i] = x[i - v - 1];y[i] = y[i - v - 1]
using namespace std;
inline int R()
{
    int r = 0;char c = getchar();while(!isdigit(c)) c = getchar();
    while(isdigit(c)) r = r * 10 + c - '0', c = getchar();return r;
}
int n, c, a, u, v;char o[7], s[16];map<string, int> m;
int F() {scanf("%s", s);return m[s] ? m[s] : m[s] = ++c;}
struct T{T *l = 0, *r = 0;int v = 0;void u() {v = 0;if
(l) v += l->v;if(r) v += r->v;}}*x[100050], *y[100050];
void M(int l, int x, int s, int t, T *&p)
{
    p = p ? new T(*p) : new T;if(s == t) {p->v += x;return;}G;if
    (l <= m) M(l, x, s, m, p->l);else M(l, x, m + 1, t, p->r);p->u();
}
int Q(int l, int r, int s, int t, T *p)
{
    if(!p) return 0;if(l <= s && t <= r) return p->v;G;int q = 0;if(l <= m)
    q += Q(l, r, s, m, p->l);if(r > m) q += Q(l, r, m + 1, t, p->r);return q;
}
int main()
{
    n = R();for(int i = 1;i <= n;++i)
    {
        scanf("%s", o);U(0);switch(o[0])
        {
            case 's': I;D;M(v = R(), 1, 1, 1e9, y[i]);S(v);break;case 'r':
            I;D;S(0);break;case 'q': I;printf("%d\n", --u <= 0 ? u : Q(1, u,
            1, 1e9, y[i]));fflush(stdout);break;case 'u': a = R();U(a);break;
        }
    }
    return 0;
}
posted @ 2022-09-28 20:11  5k_sync_closer  阅读(0)  评论(0编辑  收藏  举报  来源