「TJOI2019」甲苯先生的滚榜

题目链接

问题分析

参照数据范围,我们需要一个能够在\(O(n\log n)\)复杂度内维护有序数列的数据结构。那么平衡树是很好的选择。参考程序中使用带旋Treap。

参考程序

#pragma GCC optimize( 3 )
#include <cstdio>
#include <ctime>
#include <algorithm>

namespace Treap {
    struct member {
        int Number, Time;
        bool operator > ( const member Other ) const {
            return Number < Other.Number || Number == Other.Number && Time > Other.Time;
        };
        bool operator == ( const member Other ) const {
            return Number == Other.Number && Time == Other.Time;
        };
        bool operator < ( const member Other ) const {
            return Number > Other.Number || Number == Other.Number && Time < Other.Time;
        }
    };
    struct node {
        int Random, Size, Cnt;
        member Value;
        node *LeftChild, *RightChild;
    };
    void Collect( node *A ) {
        A->Size = A->Cnt + ( ( A->LeftChild != NULL ) ? A->LeftChild->Size : 0 ) + ( ( A->RightChild != NULL ) ? A->RightChild->Size : 0 );
        return;
    }
    node *LeftRotate( node *A ) {
        node *B = A->RightChild; A->RightChild = B->LeftChild; B->LeftChild = A; Collect( A ); Collect( B ); return B;
    }
    node *RightRotate( node *A ) {
        node *B = A->LeftChild; A->LeftChild = B->RightChild; B->RightChild = A; Collect( A ); Collect( B ); return B;
    }
    node *Insert( node *Rt, member x ) {
        if( Rt == NULL ) {
            Rt = new node;
            Rt->Random = rand() % 1000000000; Rt->Value = x; Rt->Size = 1; Rt->Cnt = 1; Rt->LeftChild = Rt->RightChild = NULL;
            return Rt;
        }
        ++( Rt->Size );
        if( Rt->Value == x ) { ++( Rt->Cnt ); return Rt; }
        if( Rt->Value < x ) {
            Rt->RightChild = Insert( Rt->RightChild, x ); if( Rt->RightChild->Random < Rt->Random ) Rt = LeftRotate( Rt );
        } else {
            Rt->LeftChild = Insert( Rt->LeftChild, x ); if( Rt->LeftChild->Random < Rt->Random ) Rt = RightRotate( Rt );
        }
        return Rt;
    }
    node *Del( node *Rt, member x ) {
        if( Rt == NULL ) { printf( "No such number called %d\n", x ); return Rt; }
        if( Rt->Value == x ) {
            if( Rt->Cnt > 1 ) { --( Rt->Cnt ); --( Rt->Size ); return Rt; }
            if( Rt->LeftChild == NULL ) { node *T = Rt->RightChild; delete Rt; return T; }
            if( Rt->RightChild == NULL ) { node *T = Rt->LeftChild; delete Rt; return T; }
            if( Rt->LeftChild->Random <= Rt->RightChild->Random ) {
                Rt = RightRotate( Rt ); --( Rt->Size ); Rt->RightChild = Del( Rt->RightChild, x ); return Rt;
            } else {
                Rt = LeftRotate( Rt ); --( Rt->Size ); Rt->LeftChild = Del( Rt->LeftChild, x ); return Rt;
            }
            return Rt;
        }
        --( Rt->Size );
        if( Rt->Value < x ) { Rt->RightChild = Del( Rt->RightChild, x ); return Rt; }
        else { Rt->LeftChild = Del( Rt->LeftChild, x ); return Rt; }
        return Rt;
    }
    int QueryR( node *Rt, member x ) {
        int Ans = 0;
        for( ; Rt != NULL; ) {
            if( Rt->Value == x ) return Ans + ( ( Rt->LeftChild != NULL ) ? Rt->LeftChild->Size : 0 ) + 1;
            if( Rt->Value < x ) {
                Ans += ( ( Rt->LeftChild != NULL ) ? Rt->LeftChild->Size : 0 ) + Rt->Cnt;
                Rt = Rt->RightChild;
            } else Rt = Rt->LeftChild;
        }
        return Ans + 1;
    }
    member QueryN( node *Rt, int x ) {
        for( ; Rt != NULL; ) {
            int Rc = 0; if( Rt->LeftChild != NULL ) Rc = Rt->LeftChild->Size;
            if( x > Rc && x <= Rc + Rt->Cnt ) return Rt->Value;
            if( x <= Rc ) Rt = Rt->LeftChild; else { x -= Rc + Rt->Cnt; Rt = Rt->RightChild; }
        }
        printf( "QueryNumber Failed.\n" );
        return ( member ){ -1, -1 };
    }
    member pre( node *Rt, member x ) {
        member Ans = x;
        for( ; Rt != NULL; ) if( Rt->Value < x ) { Ans = Rt->Value; Rt = Rt->RightChild; } else Rt = Rt -> LeftChild;
        if( Ans == x ) printf( "Query Pre Failed.\n" );
        return Ans;
    }
    member suc( node *Rt, member x ) {
        member Ans = x;
        for( ; Rt != NULL; ) if( Rt->Value > x ) { Ans = Rt->Value; Rt = Rt->LeftChild; } else Rt = Rt -> RightChild;
        if( Ans == x ) printf( "Query Suc Failed.\n" );
        return Ans;
    }
    struct treap {
        node *Root;
        void clear() { delete [] Root; Root = NULL; srand( time( NULL ) ); return; }
        void insert( member x ) { Root = Insert( Root, x ); return; }
        void Delete( member x ) { Root = Del( Root, x ); return; }
        int QueryRank( member x ) { return QueryR( Root, x ); }
        member QueryNumber( int x ) { return QueryN( Root, x ); }
        member Pre( member x ) { return pre( Root, x ); }
        member Suc( member x ) { return suc( Root, x ); }
    };
} //Treap

Treap::treap Tree;

namespace UI {
    typedef unsigned int ui ;
    ui randNum( ui& seed , ui last , const ui m){
        seed = seed * 17 + last ; return seed % m + 1;
    }
    ui seed, last = 7;
    void InSeed() { scanf( "%llu", &seed ); return; }
} //UI

const int Maxm = 100010;
Treap::member Rec[ Maxm ];

void MAIN() {
    Tree.clear();
    int n, m; scanf( "%d%d", &m, &n ); UI::InSeed();
    for( int i = 1; i <= m; ++i ) {
        Tree.insert( ( Treap::member ){ 0, 0 } );
        Rec[ i ] = ( Treap::member ){ 0, 0 };
    }
    for( int i = 1; i <= n; ++i ) {
        int x = UI::randNum( UI::seed, UI::last, m );
        int y = UI::randNum( UI::seed, UI::last, m );
        Tree.Delete( Rec[ x ] );
        ++Rec[ x ].Number;
        Rec[ x ].Time += y;
        Tree.insert( Rec[ x ] );
        UI::last = Tree.QueryRank( Rec[ x ] ) - 1;
        printf( "%llu\n", UI::last );
    }
    return;
}

int main() {
    int TestCases; scanf( "%d", &TestCases );
    for( ; TestCases--; ) MAIN();
    return 0;
}

原文地址:https://www.cnblogs.com/chy-2003/p/11215514.html

时间: 2024-08-30 18:22:18

「TJOI2019」甲苯先生的滚榜的相关文章

luogu P5338 [TJOI2019]甲苯先生的滚榜

传送门 首先,排名系统,一看就知道是原题,可以上平衡树来维护 然后考虑一种比较朴素的想法,因为我们要知道排名在一个人前面的人数,也就是AC数比他多的人数+AC数一样并且罚时少的人数,所以考虑维护那两个东西.AC数更多的人数显然可以直接上树状数组.后者的话可以对每一种AC数开值域线段树,存每个罚时有多少人,注意到罚时之和不会超过\(1.5*10^6\),所以动态开点线段树可以轻松解决.然后每次有个人AC数和罚时改变就先在原来的位置-1,然后在新位置+1.每次询问就是树状数组上AC数\(>\)当前A

宜信技术学院上榜「2019中国技术品牌影响力企业榜」

12月25日,开发者社区和专业技术媒体SegmentFault发布了2019 中国技术品牌影响力企业榜.凭借过去一年对宜信科技成果和技术实践的传播以及在金融科技领域探索方面的积极努力,宜信技术学院登上榜单前10. 宜信技术学院成立于2017年,专注于分享与传播宜信技术团队的研发实践成果与技术解决方案.经过多年的探索和实践,宜信技术团队沉淀了海量的软件研发经验,特别是在金融科技领域,积极探索软件技术在金融服务与金融安全保障方面的智能化.创新性的技术解决方案,并取得了非常多的技术成果.2019年,围

过去这几十年,分布式系统的「数据一致性」精华都在这了!

阅读目录 为什么需要事务 事务的来源 分布式系统中的事务问题 分布式事务的解决方案 结语 暂时还未涉及的园友们,可以收藏防身哦~ 本文是本系列的第三篇.与前两篇<不知道是不是最通俗易懂的<数据一致性>剖析了>.<烦人的数据不一致到底怎么解决?——通过“共识”达成数据一致性>形成完整的「数据一致性」合集. 一.为什么需要事务 如果说「共识」解决的是「水平」问题,那么「事务」解决的是「垂直」问题.是如何让一条绳上的蚂蚱共同起舞? 事务只是一个计算机术语,而事务的体现形式其实

上「知乎」,与 SAP 一同探索「独角兽」成长的甜蜜与烦恼

独角兽企业,一般指创办时间相对较短.估值超过10亿美元的创业企业.如今,全球独角兽公司榜单上的中国面孔越来越多.2017年,全球十大独角兽企业中,将近一半来自中国. 这些如同「开挂」一般迅速成长的企业,虽然饱受众多媒体与用户的青睐,更是资本市场的宠儿,但也不免要经历其它企业一般成长的阵痛.尤其是在「一夜长大」的过程中,独角兽们历经了员工数量的迅速膨胀.组织机构的急速扩张.业务方向的激烈动荡,甚至是外部环境的风云变幻. 可是他们终究成长了起来,如同许多年前第一把点燃中国民营经济之火的初代创业者一般

AC日记——「HNOI2017」单旋 LiBreOJ 2018

#2018. 「HNOI2017」单旋 思路: set+线段树: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define maxtree maxn<<2 int val[maxtree],tag[maxtree],L[maxtree],R[maxtree],mid[maxtree]; int op[maxn],ki[maxn],bi[maxn],cnt,size,n,ch[maxn]

「随笔」基于当下的思考

马德,说好的技术blog,变成日记本了... 下午的时候莫名其妙的感到很颓废,因为自己的不够强大感到忧虑和危机感十足.现在每每行走在技术的道路上,常觉得如履薄冰,如芒在背. 上大学之前和现在的心态其实差别挺大的,视野的开阔远远不止局限于自己的脚下.不过,这里的「上大学之前」只是一个时间描述词,并不觉得大学是最适合学习的地方,我很失望. 世界上的人无论性别,区域,宗教,兴趣爱好,总可以在互联网上找到志趣相同的人,总是可以不断打破自己的常识与惯性思维.总是有在相同领域比自己更强的人,挺好的. 关于知

「Unity」与iOS、Android平台的整合:3、导出的Android-Studio工程

本文属于「Unity与iOS.Android平台的整合」系列文章之一,转载请注明出处. Unity默认导出的是Android-Eclipse工程,毕竟Eclipse for Android开发在近一两年才开始没落,用户量还是非常巨大的. 个人认为AndroidStudio非常好用,能轻易解决很多Eclipse解决不了或者很难解决的问题. 所以我将Unity导出的Andoid工程分为Eclipse和AndroidStudio两部分. 不过我之后的相关内容都会使用AndroidStudio,希望依然

大数据和「数据挖掘」是何关系?---来自知乎

知乎用户,互联网 244 人赞同 在我读数据挖掘方向研究生的时候:如果要描述数据量非常大,我们用Massive Data(海量数据)如果要描述数据非常多样,我们用Heterogeneous Data(异构数据)如果要描述数据既多样,又量大,我们用Massive Heterogeneous Data(海量异构数据)--如果要申请基金忽悠一笔钱,我们用Big Data(大数据) 编辑于 2014-02-2817 条评论感谢 收藏没有帮助举报作者保留权利 刘知远,NLPer 4 人赞同 我觉得 大数据

开放的智力8:实用「成功学」

可实现的「成功学」 现在我想为这里的年轻人介绍一种可实现的「成功学」.希望这个我自创的理论,可以改变很多人的一生. 当我们评价一个事情值不值得去做.应该花多少精力去做的时候,应该抛弃单一的视角,而是分两个不同的维度来看,一是该事件将给我带来的收益大小(认知.情感.物质.身体方面的收益皆可计入),即「收益值」:二是该收益随时间衰减的速度,我称为「收益半衰期」,半衰期长的事件,对我们的影响会持续得较久较长. 这两个维度正交以后就形成了一个四象限图.我们生活.学习和工作中的所有事情都可以放进这个图里面