HDU 5096 题解

题目大意

实现一个acm的排名系统。
S a:b:c:d
b队在a分钟提交了c题,状态为d
如果b对在5分钟内有其他有效提交,则这次提交为无效提交。如果没有AC,这道题的罚时+20分钟。通过一题后才累加这道题的罚时。
R a
查询a队的排名
Q a
查询排名为a的队伍编号

排名方式:
以AC题数为第一关键字,罚时为第二关键字,最后AC时间为第三关键字。
对于没有A题的队伍,编号小的队靠前。

我的做法

替罪羊树

AC一题罚时就-10000000
其他的直接搞。

#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
int lsa[10010];
int lst[10010];
int ac[10010][11];
int fti[100010][11];
int ti[10010];
struct cmp
{
    bool operator ()(int a,int b)
    {
        return lsa[a]<lsa[b];
    }
};
struct tree
{
    int sum;
    int size;
    int v;
    tree *ls,*rs;
    set<int,cmp> t;
    tree()
    {
        sum=0;
        size=0;
        v=0;
        ls=rs=0;
    }
};
tree *top;
tree **needbuild;
tree a[10010];
int cnt;
void mt(tree *&p)
{
    p->sum=p->t.size();
    p->size=1;
    if(p->ls)
    {
        p->sum+=p->ls->sum;
        p->size+=p->ls->size;
    }
    if(p->rs)
    {
         p->sum+=p->rs->sum;
         p->size+=p->rs->size;
    }
}
void _insert(tree *&p,int x)
{
    if(!p)
    {
        p=new tree;
        p->sum=p->size=1;
        p->v=ti[x];
        p->t.clear();
        p->t.insert(x);
        return;
    }
    if(p->v==ti[x])
    {
        p->sum++;
        p->t.insert(x);
        return;
    }
    if(ti[x]<p->v)
     _insert(p->ls,x);
    else
     _insert(p->rs,x);
    mt(p);
    if(p->ls&&p->ls->size>0.7*p->size||p->rs&&p->rs->size>0.7*p->size)
     needbuild=&p;
}
void prebuild(tree *&p)
{
    if(p->ls)
     prebuild(p->ls);
    if(p->size)
     a[++cnt]=*p;
    if(p->rs)
     prebuild(p->rs);
    delete p;
    p=0;
}
void build(tree *&p,int l,int r)
{
    if(l>r)
     return;
    int mid=(l+r)>>1;
    p=new tree(a[mid]);
    p->ls=p->rs=0;
    build(p->ls,l,mid-1);
    build(p->rs,mid+1,r);
    mt(p);
}
void insert(int x)
{
    needbuild=0;
    _insert(top,x);
    if(needbuild)
    {
        cnt=0;
        prebuild(*needbuild);
        build(*needbuild,1,cnt);
    }
}
void del(tree *&p,int x)
{
    if(!p)
     return;
    if(p->v==ti[x])
    {
        p->sum--;
        p->t.erase(p->t.find(x));
        return;
    }
    if(ti[x]<p->v)
     del(p->ls,x);
    else
     del(p->rs,x);
    mt(p);
}
int find(tree *&p,int x)
{
    if(ti[x]>p->v)
     return find(p->rs,x);
    int rs=0;
    if(p->rs)
     rs=p->rs->sum;
    if(ti[x]<p->v)
     return find(p->ls,x)+p->t.size()+rs;
    return rs+1;
}
int kth(tree *&p,int x)
{
    if(!p||x<=0||x>p->sum)
     return 0;
    int rs=0;
    if(p->rs)
     rs=p->rs->sum;
    if(x<=rs)
     return kth(p->rs,x);
    if(p->t.size()&&x==rs+1)
     return *(p->t.begin());
    return kth(p->ls,x-rs-p->t.size());
}
void remove(tree *&p)
{
    if(p->ls)
     remove(p->ls);
    if(p->rs)
     remove(p->rs);
    delete p;
    p=0;
}
int main()
{
    int n,m;
    char op[50];
    while(~scanf("%d%d",&n,&m))
    {
        int i;
        if(top)
         remove(top);
        fill(lst+1,lst+n+1,-5);
        memset(ac,0,sizeof(ac));
        memset(fti,0,sizeof(fti));
        memset(ti,0,sizeof(ti));
        for(i=1;i<=n;i++)
        {
            lsa[i]=i-n-1;
            insert(i);
        }
        int min,id,res,no;
        char c;
        int now=0;
        int tt=0;
        int ttt=0;
        while(~scanf("%s",op)&&op[0]!='C')
        {
            ttt++;
            if(op[0]=='S')
            {
                scanf("%d:%d:%c:%d",&min,&no,&c,&res);
                 no++;
                 id=c-'A'+1;
                 if(min-lst[no]<5||ac[no][id])
                  continue;
                 lst[no]=min;
                 if(res==1)
                 {
                     tt++;
                     printf("[%d][%c]\n",no-1,c);
                     del(top,no);
                     if(top->sum*2<=top->size)
                     {
                         cnt=0;
                         prebuild(top);
                         build(top,1,cnt);
                     }
                     lsa[no]=++now;
                     ac[no][id]=1;
                     ti[no]+=10000000-fti[no][id]-min;
                     insert(no);
                 }
                 else
                  fti[no][id]+=20;
            }
            else if(op[0]=='R')
            {
                 scanf("%d",&no);
                 no++;
                printf("%d\n",find(top,no));
            }
            else
            {
                 scanf("%d",&no);
                 printf("%d\n",kth(top,no)-1);
            }
        }
        scanf("%s",op);
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值