【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\n",ans);
    }

    fclose(stdin);
    fclose(stdout);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/sslgz_yyc/article/details/81022605
今日推荐