要求操作是在线且完全可持久化的。
N≤20000,M≤20000,K≤100
先考虑一个简单的问题, K=1 。那么很显然,由于运算满足结合律,那么我们可以直接用一颗简单的可持久化Treap就可以完成所有的操作。
接下来考虑 k>1 。
首先很显然的,假设当前要求出 F(S) ,其中 S 为一个表达式,我们可以先找到 S 中优先级最小的运算符,假设其为 Si ,那么我们可以先递归求出 F(S0..i−1) 与 F(Si+1..n) 的值,然后求出这两个值在 Si 作用下的值。
那么我们可以尝试对可持久化Treap做一些修改,使其满足一个节点 i 所代表的优先级是其所代表的整个区间中优先级最小的。那么我们依然可以简单的对两个子树分别求值再合并。
可以发现的是,我们只需要在 merge(a,b) 时,强制保证是优先级大的 Treap 合并到优先级小的 Treap 中就好了。
现在的问题是复杂度是否会出问题。但事实上,通过计算,可以发现这样子实现的 Treap 的期望深度为 O(k+logn) 的,没有任何问题。
#include "expr.h"
#include <cstdio>
#include <algorithm>
#include <cstring>
#define fe first
#define se second
using namespace std;
const int MAXN = 30000005;
typedef pair<int,int> P;
struct Node
{
int l,r,size,ch;
Data sum,val;
bool rev;
}T[MAXN];
Data bak;
int Ord[MAXN],cnt,Cur_id;
int Newnode(int x)
{
T[++ cnt] = T[x];
return cnt;
}
void Update(int x)
{
T[x].size = T[T[x].l].size + T[T[x].r].size + 1;
if (T[x].ch < 1000 && T[x].l && T[x].r) T[x].sum = F(T[T[x].l].sum,T[T[x].r].sum,T[x].ch); else
T[x].sum = T[x].val;
}
void Mark(int &x)
{
if (!x) return;
T[++ cnt] = T[x];
T[cnt].rev ^= 1;
swap(T[cnt].l,T[cnt].r);
x = cnt;
}
void Down(int x)
{
if (!T[x].rev) return;
Mark(T[x].l),Mark(T[x].r),T[x].rev = 0;
}
bool Cmp(int a,int b)
{
if (T[a].ch == T[b].ch) return (rand() % (T[a].size + T[b].size) < T[a].size);
return T[a].ch < T[b].ch;
}
int Merge(int a,int b)
{
if (!a) return b;
if (!b) return a;
Down(a),Down(b);
int nt;
if (Cmp(a,b))
{
nt = Newnode(a);
T[nt].r = Merge(T[a].r,b);
} else
{
nt = Newnode(b);
T[nt].l = Merge(a,T[b].l);
}
Update(nt);
return nt;
}
P Split(int x,int size)
{
if (!x) return P(0,0);
Down(x);
P tmp;
if (T[T[x].l].size >= size)
{
tmp = Split(T[x].l,size);
int nt = Newnode(x);
T[nt].l = tmp.se;
Update(nt);
return P(tmp.fe,nt);
} else
{
tmp = Split(T[x].r,size - T[T[x].l].size - 1);
int nt = Newnode(x);
T[nt].r = tmp.fe;
Update(nt);
return P(nt,tmp.se);
}
}
// precedences: 1 ~ k, larger is higher
void init(int test_id, int n, int m, int k, const Data *a, const int *ops)
{
bak = a[0];
for(int i = n - 1;i >= 0;i --)
{
int nt = Newnode(0);
T[nt].size = 1,T[nt].val = T[nt].sum = a[i],T[nt].ch = (1 << 30);
Ord[0] = Merge(nt,Ord[0]);
if (i)
{
nt = Newnode(0),T[nt].size = 1,T[nt].ch = ops[i],T[nt].sum = T[nt].val = bak;
Ord[0] = Merge(nt,Ord[0]);
}
}
}
Data modify_data(int id, int pos, Data x)
{
++ Cur_id;
(pos <<= 1) |= 1;
P a = Split(Ord[id],pos),b = Split(a.fe,pos - 1);
int cr = Newnode(b.se);
T[cr].val = T[cr].sum = x,T[cr].ch = (1 << 30);
Ord[Cur_id] = Merge(Merge(b.fe,cr),a.se);
return T[Ord[Cur_id]].sum;
}
// modify the operator between pos and pos - 1
Data modify_op(int id, int pos, int new_op)
{
++ Cur_id;
pos <<= 1;
P a = Split(Ord[id],pos),b = Split(a.fe,pos - 1);
int cr = Newnode(b.se);
T[cr].ch = new_op;T[cr].sum = T[cr].val = bak;
Ord[Cur_id] = Merge(Merge(b.fe,cr),a.se);
return T[Ord[Cur_id]].sum;
}
Data reverse(int id, int l, int r)
{
++ Cur_id;
(l <<= 1) |= 1,(r <<= 1) |= 1;
P a = Split(Ord[id],r),b = Split(a.fe,l - 1);
Mark(b.se);
Ord[Cur_id] = Merge(Merge(b.fe,b.se),a.se);
return T[Ord[Cur_id]].sum;
}