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;
}