Treap LA5031

来源:互联网 发布:金融类的工作知乎 编辑:程序博客网 时间:2024/05/16 12:19

动态二插排序树的一种常用实现算法:Treap。

从树根向下递归时当然都是一般的BST方式,左小又大,一步步向下;而向上回溯时却是采用维护最大堆的方式,同时为了维护二叉排序树的基本特性,每次不是直接交换节点,而是旋转;

从基本的Treap中为了解题,衍生出了名次树,每个节点用一个数据记录该子树所有节点数,可以完成查询第K大数(第K小数),找任给的x在当前树中的名次;

注意maintain的实现方式和位置,位置很重要,基本原则就是每次更新了节点(添加,删除,旋转),最后都要维护一下;

本题其实还要复杂的多,用到了启发式合并(大概就是从后往前,逆序的意思?),然后同时维护多个Treap树,除了基本的insert,remove,还要完成合并两个树mergoto的操作,自然要用到基本的并查集,哎,白书上说让大家独立手拍;

这题综合性相当强,时间复杂度是n*logn*logn。

#include <cstdlib>struct node {    node *ch[2];    int r;    int v;    int s;    node(int v):v(v) { ch[0]=ch[1]=NULL; r=rand(); s=1; }    bool operator < (const node& rhs) const {        return r < rhs.r;    }    int cmp(int x) const {        if (x==v) return -1;        return x<v? 0 : 1;    }    void maintain() {        s=1;        if (ch[0]!=NULL) s+=ch[0]->s;        if (ch[1]!=NULL) s+=ch[1]->s;    }};void rotate(node* &o,int d){    node* k= o->ch[d^1];    o->ch[d^1] = k->ch[d];    k->ch[d] = o;    o->maintain();    k->maintain();    o = k;}void insert(node* &o,int x) {    if (o==NULL) o=new node(x);    else {        int d=(x < o->v?0 :1 );        insert(o->ch[d],x);        if (o->ch[d] > o) rotate(o,d^1);    }    o->maintain();}void remove(node* &o,int x) {    int d=o->cmp(x);    if (d==-1) {        node* u=o;        if (o->ch[0]!=NULL && o->ch[1]!=NULL) {            int d2= (o->ch[0]>o->ch[1]? 1 : 0);            rotate(o,d2);            remove(o->ch[d2],x);        }else {            if (o->ch[0] ==NULL) o=o->ch[1];            else o=o->ch[0];            delete u;        }    }else        remove(o->ch[d],x);    if (o!=NULL) o->maintain();}#include <cstdio>#include <cstring>#include <vector>//#include <fstream>using namespace std;const int maxc= 500000+10;struct Commond {    char type;    int x, p;}commonds[maxc];const int maxn=20000+10;const int maxm=60000+10;int n, m, weight[maxn], from[maxm], to[maxm], removed[maxm];int pa[maxn];int findset(int x) {    return pa[x]!=x ? pa[x]=findset(pa[x]) : x;}node* root[maxn];int kth(node* o,int k){    if (o==NULL || k<=0 || k>o->s) return 0;    int s=(o->ch[1]==NULL ? 0 : o->ch[1]->s );    if (k==s+1) return o->v;    else if (k<=s) return kth(o->ch[1],k);    else return kth(o->ch[0],k-s-1);}void mergeto(node* &src,node* &dest){    if (src->ch[0]!=NULL) mergeto(src->ch[0],dest);    if (src->ch[1]!=NULL) mergeto(src->ch[1],dest);    insert(dest,src->v);    delete src;    src=NULL;}void removetree(node* &x) {    if (x->ch[0]!=NULL) removetree(x->ch[0]);    if (x->ch[1]!=NULL) removetree(x->ch[1]);    delete x;    x=NULL;}void add_edge(int x) {    int u=findset(from[x]), v=findset(to[x]);    if (u!=v) {        if (root[u]->s<root[v]->s) {            pa[u]=v; mergeto(root[u],root[v]);        }        else {            pa[v]=u; mergeto(root[v],root[u]);        }    }}int query_cnt;long long query_tot;void query(int x,int k){    query_cnt++;    query_tot += kth(root[findset(x)],k);}void change_weight(int x,int v) {    int u=findset(x);    remove(root[u],weight[x]);    insert(root[u],v);    weight[x]=v;}int main(){//    freopen("1.in","r",stdin);    int kase=0;    while (scanf("%d%d",&n, &m)==2 && n) {        for (int i=1;i<=n;i++) scanf("%d",&weight[i]);        for (int i=1;i<=m;i++) scanf("%d%d",&from[i],&to[i]);        memset(removed,0,sizeof(removed));        int c=0;        for (;;) {            char type;            int x, p=0, v=0;            scanf(" %c",&type);            if (type=='E') break;            scanf("%d",&x);            if (type=='D') removed[x]=1;            if (type=='Q') scanf("%d",&p);            if (type=='C') {                scanf("%d",&v);                p=weight[x];                weight[x]= v;            }            commonds[c++]= (Commond) {type,x,p};        }        for (int i=1;i<=n;i++) {            pa[i]=i; if (root[i]!=NULL) removetree(root[i]);            root[i]= new node(weight[i]);        }        for (int i=1;i<=m;i++)            if (!removed[i]) add_edge(i);        query_tot= query_cnt = 0;        for (int i=c-1;i>=0;i--) {            if (commonds[i].type=='D') add_edge(commonds[i].x);            if (commonds[i].type=='Q') query(commonds[i].x,commonds[i].p);            if (commonds[i].type=='C') change_weight(commonds[i].x,commonds[i].p);        }        printf("Case %d: %.6lf\n",++kase,query_tot/(double)query_cnt);    }    return 0;}


原创粉丝点击