• 【NOIP2015模拟10.27】魔道研究


    Description
    “我希望能使用更多的魔法。不对,是预定能使用啦。最终我要被大家称呼为大魔法使。为此我决定不惜一切努力。”
    ——《The Grimoire of Marisa》雾雨魔理沙
    魔理沙一如既往地去帕秋莉的大图书馆去借魔导书(Grimoire) 来学习魔道。
    最开始的时候,魔理沙只是一本一本地进行研究。然而在符卡战中,魔理沙还是战不过帕秋莉。
    好在魔理沙对自己的借还和研究结果进行了记录,从而发现了那些魔导书的精妙之处。
    帕秋莉的那些魔导书,每本都有一个类别编号ti 和威力大小pi。而想要获得最有威力的魔法,就必须同时研究一些魔导书。而研究的这些魔导书就必须要满足,类别编号为T 的书的本数小于等于T,并且总共的本数小于等于一个给定的数N。而研究这些魔导书之后习得的魔法的威力就是被研究的魔导书的威力之和。
    为了击败帕秋莉,魔理沙想要利用自己发现的规律来获得最有威力的魔法。
    她列出了计划中之后M 次的借还事件,并想要知道每个事件之后自己所能获得的魔法的最大威力。可她忙于魔法材料——蘑菇的收集,于是这个问题就交给你来解决了。

    Input
    输入文件grimoire.in。
    第1 行2 个整数N,M,分别表示魔理沙能研究的魔导书本数的上限和她的借还事件数。
    之后M 行,每行的形式为“op t p”(不含引号)。Op 为“BORROW” 或“RETURN”,分别表示借书和还书。T 为一个整数,表示这本书的类别编号。P为一个整数,表示这本书的威力大小。注意,还书时如果有多本书满足类别编号为t,威力大小为p,这表明这些书都是相同的,魔理沙会任选其中一本书还回去。如果你问我为何会有相同的书,多半因为这是魔导书吧。

    Output
    输出文件grimoire.out。
    一共M 行,每行一个整数,即每个事件之后的最大威力。

    Sample Input
    5 10
    BORROW 1 5811
    BORROW 3 5032
    RETURN 3 5032
    BORROW 3 5550
    BORROW 5 3486
    RETURN 1 5811
    RETURN 3 5550
    BORROW 4 5116
    BORROW 3 9563
    BORROW 5 94

    Sample Output
    5811
    10843
    5811
    11361
    14847
    9036
    3486
    8602
    18165
    18259

    Data Constraint
    对于5% 的数据,1 <= t,N,M <= 50。
    对于10% 的数据,1 <= t,N,M <= 100。
    对于30% 的数据,1 <= t,N,M<= 10 000。
    另有30% 的数据,1 <= p <= 1 000。
    对于100% 的数据,1 <= t,N,M <= 300 000,1<= p<= 1 000 000 000。
    另外,总共有30% 的数据,满足没有“RETURN” 操作。这部分数据均匀分布。
    .
    .
    .
    .
    .

    程序:
    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define max(a,b) (a>b?a:b)
    #define min(a,b) (a<b?a:b)
    #define Len 1000000000
    using namespace std;
    
    long long tr[20000001][5];
    int n,m,i,j,k,l,x,y,len,S,S2;
    char s[20];
    long long ans;
    
    void New(int t,int x)
    {
        if (!tr[t][x])
        tr[t][x]=++len;
    }
    
    void change(int t,int l,int r,int x,int s)
    {
        int mid=(l+r)/2;
    
        tr[t][2]+=s;
        if (tr[t][2]<0)
        cout<<tr[t][2]<<endl;
    
        tr[t][3]+=s*x;
    
        if (l==r)
        {
            if (tr[t][2])
            tr[t][4]=x;
            else
            tr[t][4]=0;
    
            return;
        }
    
        if (x<=mid)
        {
            New(t,0);
            change(tr[t][0],l,mid,x,s);
        }
        else
        {
            New(t,1);
            change(tr[t][1],mid+1,r,x,s);
        }
    
        tr[t][4]=max(tr[tr[t][0]][4],tr[tr[t][1]][4]);
    }
    
    void get(int t,int l,int r,long long k)
    {
        int mid=(l+r)/2;
    
        if (l==r)
        {
            ans+=(long long)min(k,tr[t][2])*l;
            return;
        }
    
        if (tr[tr[t][1]][2]<=k)
        {
            ans+=tr[tr[t][1]][3];
    
            if (tr[tr[t][0]][2] && k>tr[tr[t][1]][2])
            get(tr[t][0],l,mid,k-tr[tr[t][1]][2]);
        }
        else
        {
            if (tr[tr[t][1]][2])
            get(tr[t][1],mid+1,r,k);
        }
    }
    
    void Get(int t,int l,int r,int x,int y)
    {
        int mid=(l+r)/2;
    
        if (x<=l && r<=y)
        {
            S+=tr[t][2];
            return;
        }
    
        if (x<=mid && tr[tr[t][0]][2])
        Get(tr[t][0],l,mid,x,y);
        if (mid<y  && tr[tr[t][1]][2])
        Get(tr[t][1],mid+1,r,x,y);
    }
    
    void find(int t,int l,int r,int k)
    {
        int mid=(l+r)/2;
    
        if (l==r)
        {
            if (k<=tr[t][2])
            S2=l;
            return;
        }
    
        if (tr[tr[t][1]][2]<k)
        {
            if (tr[tr[t][0]][2])
            find(tr[t][0],l,mid,k-tr[tr[t][1]][2]);
        }
        else
        {
            if (tr[tr[t][1]][2])
            find(tr[t][1],mid+1,r,k);
        }
    }
    
    int main()
    {
        freopen("grimoire.in","r",stdin);
        freopen("grimoire.out","w",stdout);
    
        scanf("%d%d",&n,&m);
        len=300001;
    
        fo(i,1,m)
        {
            scanf("%s%d%d",s,&x,&y);
    
            if (s[0]=='B')
            {
                change(x,1,Len,y,1);
    
                S=0;
                Get(x,1,Len,y,Len);
                if (S<=x)
                {
                    change(300001,1,Len,y,1);
    
                    S2=0;
                    find(x,1,Len,x+1);
                    if (S2)
                    change(300001,1,Len,S2,-1);
                }
            }
            else
            {
                S=0;
                Get(x,1,Len,y,Len);
    
                change(x,1,Len,y,-1);
                if (S<=x)
                {
                    change(300001,1,Len,y,-1);
    
                    S2=0;
                    find(x,1,Len,x);
                    if (S2)
                    change(300001,1,Len,S2,1);
                }
            }
    
            ans=0;
            get(300001,1,Len,n);
    
            printf("%lld
    ",ans);
        }
    
        fclose(stdin);
        fclose(stdout);
    
        return 0;
    }
  • 相关阅读:
    mem 预留内存
    关于内核反汇编,同时显示源文件
    读些笔记
    platform设备驱动
    glut 右键子菜单
    获取HINSTANCE
    window窗口样式style
    opengl 直线拾取
    glut弹出式菜单
    读取大恒采集卡c++代码
  • 原文地址:https://www.cnblogs.com/YYC-0304/p/9499926.html
Copyright © 2020-2023  润新知