[WC2016]鏖战表达式

前言

出题人傻逼

题目大意

是一道交互题。
初始给你一个表达式,运算符编号越大优先级越高。你可以调用F(a,b,x)表示把元素a与b做x运算符运算得到的值。
现有三种操作,修改一个元素的值、修改一个运算符、翻转一个区间,每个操作后需要返回表达式的值。
不能调用F超过10^7次。
要求在线并可持久化。

Treap大法好

一个显然的想法,每次找到优先级最小的运算符,然后分成两部分递归求解。我们需要维护一颗运算树,然后我们发现运算树其实就是一颗Treap,也就是Treap的堆关键字不能随机而是要使用对应的优先级。当然,元素的优先级为101。运算树我们不会维护,但是Treap我们就很熟悉了,而且它可以可持久化,可以修改。
于是现在问题来了:众所周知,只有堆关键字随机才可以说Treap树高期望log n。现在怎么办?去膜了一下philipsweng,优先级相同时根据子树大小随机合并即可,期望高度k+log n(不会证,感性理解)。
然后一些细节的地方:因为可持久化只要修改一个点就要建立新点所以即使下传标记也要建新点,然后运算符对应的点的key随便赋一个已知值就好不然你会发现grader弄出-1了。还有改到最后发现答案对了但是F函数调用次数太多。于是发现倒着插入就过了什么鬼。



#include "expr.h"
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=30000000+10;
int root[maxn],size[maxn],tree[maxn][2],fix[maxn];
bool bz[maxn];
Data key[maxn],num[maxn],wdc;
int i,j,k,l,mid,r,t,n,m,tot,top;
int newnode(int x){
    size[++tot]=size[x];
    tree[tot][0]=tree[x][0];
    tree[tot][1]=tree[x][1];
    fix[tot]=fix[x];
    bz[tot]=bz[x];
    key[tot]=key[x];
    num[tot]=num[x];
    return tot;
}
void update(int x){
    size[x]=size[tree[x][0]]+size[tree[x][1]]+1;
    if (fix[x]<=100&&tree[x][0]&&tree[x][1]) num[x]=F(num[tree[x][0]],num[tree[x][1]],fix[x]);else num[x]=key[x];
}
void mark(int &x){
    if (!x) return;
    int y=newnode(x);
    bz[y]^=1;
    swap(tree[y][0],tree[y][1]);
    x=y;
}
void clear(int x){
    if (bz[x]){
        mark(tree[x][0]);
        mark(tree[x][1]);
        bz[x]=0;
    }
}
bool cmp(int x,int y){
    if (fix[x]==fix[y]) return (rand()%(size[x]+size[y])<size[x]);
    else return fix[x]<fix[y];
}
void merge(int l,int r,int &x){
    if (!l||!r){
        x=l+r;
        return;
    }
    clear(l);clear(r);
    int t;
    if (cmp(l,r)){
        t=newnode(l);
        merge(tree[l][1],r,tree[t][1]);
    }
    else{
        t=newnode(r);
        merge(l,tree[r][0],tree[t][0]);
    }
    update(t);
    x=t;
}
void split(int x,int y,int &l,int &r){
    if (!x){
        l=r=0;
        return;
    }
    if (!y){
        l=0;r=x;
        return;
    }
    clear(x);
    if (size[tree[x][0]]>=y){
        split(tree[x][0],y,l,r);
        t=newnode(x);
        tree[t][0]=r;
        update(t);
        r=t;
    }
    else{
        split(tree[x][1],y-size[tree[x][0]]-1,l,r);
        t=newnode(x);
        tree[t][1]=l;
        update(t);
        l=t;
    }
}
void init(int test_id, int n, int m, int k,const Data *a, const int *ops){
    srand(time(0));
    wdc=a[0];
    top=0;
    fd(i,n,1){
        t=newnode(0);
        size[t]=1;key[t]=num[t]=a[i-1];fix[t]=101;
        merge(t,root[0],root[0]);
        if (i>1){
            t=newnode(0);
            size[t]=1;fix[t]=ops[i-1];key[t]=num[t]=wdc;
            merge(t,root[0],root[0]);
        }
    }
}
Data modify_data(int id, int pos, Data x){
    ++top;
    pos++;
    split(root[id],2*pos-1,l,r);
    split(l,2*pos-2,l,mid);
    int t=newnode(mid);
    key[t]=num[t]=x;
    merge(l,t,l);
    merge(l,r,root[top]);
    return num[root[top]];
}
Data modify_op(int id, int pos, int new_op){
    ++top;
    split(root[id],2*pos,l,r);
    split(l,2*pos-1,l,mid);
    int t=newnode(mid);
    fix[t]=new_op;
    merge(l,t,l);
    merge(l,r,root[top]);
    return num[root[top]];
}
Data reverse(int id, int l, int r){
    ++top;
    l++;r++;
    j=l,k=r;
    split(root[id],2*k-1,l,r);
    split(l,2*j-2,l,mid);
    mark(mid);
    merge(l,mid,l);
    merge(l,r,root[top]);
    return num[root[top]];
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值