【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” 操作。这部分数据均匀分布。

题解

这题一眼就可以看出是用什么数据结构维护出对于每个t的前t个,在将前t个加入另一个数据结构,最后求出答案即可。
本题可以用权值线段树来维护,建立t+1棵权值线段树,前t棵用来维护对于每个t的前t个,最后一棵用来维护答案数组,即求出前n个。
此题细节较多,需要注意。
详情参见代码:

uses math;
const
        maxn=1000000000;
var
        n,m,i,t,p,totx,totd:longint;
        s:string;
        k:int64;
        l,r,size:array[0..30000000]of longint;
        f:array[0..30000000]of int64;
        l1,r1,st,size1:array[0..10000000]of longint;
        f1:array[0..10000000]of int64;
        ch:char;
procedure get(x:longint);
begin
        inc(totx);
        l[x]:=totx;
        inc(totx);
        r[x]:=totx;
end;
procedure get1(x:longint);
begin
        inc(totd);
        l1[x]:=totd;
        inc(totd);
        r1[x]:=totd;
end;
procedure insert(v,ll,rr,x:int64);
var
        mid:int64;
begin
        inc(size[v]);
        inc(f[v],x);
        if ll=rr then
                exit;
        if l[v]=0 then
                get(v);
        mid:=(ll+rr) div 2;
        if x<=mid then
                insert(l[v],ll,mid,x)
        else
                insert(r[v],mid+1,rr,x);
end;
procedure delete(v,ll,rr,x:int64);
var
        mid:int64;
begin
        dec(size[v]);
        dec(f[v],x);
        if ll=rr then
                exit;
        mid:=(ll+rr) div 2;
        if x<=mid then
                delete(l[v],ll,mid,x)
        else
                delete(r[v],mid+1,rr,x);
end;
function find(v,ll,rr,x:int64):int64;
var
        mid:int64;
begin
        if ll=rr then
                exit(1);
        mid:=(ll+rr) div 2;
        if x<=mid then
                exit(find(l[v],ll,mid,x));
        exit(size[l[v]]+find(r[v],mid+1,rr,x));
end;
function findk(v,ll,rr,x:int64):int64;
var
        mid:int64;
begin
        if ll=rr then
                exit(ll);
        mid:=(ll+rr) div 2;
        if size[r[v]]>=x then
                exit(findk(r[v],mid+1,rr,x));
        exit(findk(l[v],ll,mid,x-size[r[v]]));
end;
procedure insert1(v,ll,rr,x:int64);
var
        mid:int64;
begin
        inc(size1[v]);
        inc(f1[v],x);
        if ll=rr then
                exit;
        mid:=(ll+rr) div 2;
        if l1[v]=0 then
                get1(v);
        if x<=mid then
                insert1(l1[v],ll,mid,x)
        else
                insert1(r1[v],mid+1,rr,x);
end;
procedure delete1(v,ll,rr,x:int64);
var
        mid:int64;
begin
        dec(size1[v]);
        dec(f1[v],x);
        if ll=rr then
                exit;
        mid:=(ll+rr) div 2;
        if x<=mid then
                delete1(l1[v],ll,mid,x)
        else
                delete1(r1[v],mid+1,rr,x);
end;
function getans(v,ll,rr,x:int64):int64;
var
        mid:int64;
begin
        if x<=0 then
                exit(0);
        if ll=rr then
                exit(ll*min(size1[v],x));
        mid:=(ll+rr) div 2;
        if x<=size1[r1[v]] then
                exit(getans(r1[v],mid+1,rr,x));
        exit(f1[r1[v]]+getans(l1[v],ll,mid,x-size1[r1[v]]));
end;
begin
        assign(input,'grimoire.in');
        reset(input);
        assign(output,'grimoire.out');
        rewrite(output);
        readln(n,m);
        totd:=1;
        for i:=1 to m do
        begin
                if i=118 then
                begin
                        st[0]:=1;
                end;
                ch:='s';
                s:='';
                while ch<>' ' do
                begin
                        read(ch);
                        s:=s+ch;
                end;
                readln(t,p);
                if s[1]='B' then
                begin
                        if st[t]=0 then
                        begin
                                inc(totx);
                                st[t]:=totx;
                        end;
                        k:=find(st[t],1,maxn,p);
                        insert(st[t],1,maxn,p);
                        if size[st[t]]-k+1<=t then
                        begin
                                if size[st[t]]<=t then
                                        insert1(1,1,maxn,p)
                                else
                                begin
                                        k:=findk(st[t],1,maxn,t+1);
                                        delete1(1,1,maxn,k);
                                        insert1(1,1,maxn,p);
                                end;
                        end;
                end
                else
                begin
                        k:=find(st[t],1,maxn,p);
                        if size[st[t]]-k+1<=t then
                        begin
                                if size[st[t]]<=t then
                                        delete1(1,1,maxn,p)
                                else
                                begin
                                        k:=findk(st[t],1,maxn,t+1);
                                        delete1(1,1,maxn,p);
                                        insert1(1,1,maxn,k);
                                end;
                        end;
                        delete(st[t],1,maxn,p);
                end;
                writeln(getans(1,1,maxn,n));
        end;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值