WC2016 expr

题目大意

这里写图片描述

要求操作是在线且完全可持久化的。

N20000,M20000,K100

题解

先考虑一个简单的问题, K=1 。那么很显然,由于运算满足结合律,那么我们可以直接用一颗简单的可持久化Treap就可以完成所有的操作。

接下来考虑 k>1

首先很显然的,假设当前要求出 F(S) ,其中 S 为一个表达式,我们可以先找到S中优先级最小的运算符,假设其为 Si ,那么我们可以先递归求出 F(S0..i1) 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;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值