2018.07.12【2018提高组】模拟B组 【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” 操作。这部分数据均匀分布。

#题解
久违的一道数据结构裸题,大家对此垂诞三尺,把此题当做idea题乱搞。
真的好多idea。
有用权值线段树的,有用splay平衡树的,还有的说要n^2过百万的。
额。
然而我看错了题,想出个绝妙的做法,想着ac,实则GG。

那就先讲讲题意。
题意很重要!
有t种书,每次操作在某种书中添加或删除之前加入的某本书。
然后把第i种书中的前i大威力的书加入那个玛丽莎的读书清单内。每次操作结束后回答读书清单中前n大的书的威力之和。
呵呵,这个题意很完整了,应该都看得懂。

那么我们挖掘一下信息,发现,操作分为——加入、删除、查询第k大。
这不就是权值线段树么?

于是乎正解就出来了。

首先,我对于每种书都建立一颗权值线段树,保存的是书在此区间出现的次数和书威力之的和。
这样之我们还需要建立一棵大的权值线段树,也就是保存读书清单。
那么我们对于每次操作,我们直接在每种书中查询修改,然后呢,我们就可以很完美地完成对于每种书的第k大的威力值之和。
于是,我们再去看看大的权值线段树。
假设我们现在新加入一个x威力的书,那么我们对于清单,我设当前选入的点为a1,a2,a3……ai.
若x比ai大,那么在清单中要把ai删除,然后再加入。那么这样就可以很好地搞搞阵啦。

具体如何维护可以看看标程——
都是打完一遍然后copy一遍改改就好了,懒得再打
真·code

uses math;
type
        new=record
                a:array of int64;
        end;
        new1=record
                a:array of boolean;
        end;
var
        i,j,k,l,n,m,zb,tot,maxx:longint;
        ans,answer:int64;
        tree,size,size1,tree1:array[0..13000000] of int64;
        left,right,root,root1,left1,right1:array[0..13000000] of longint;
        ch:char;
        q,wz,last,val,gss,t,p,jl:array[1..300000] of int64;
        a,b,time,js,xdtree:array[1..300000] of new;
procedure qsort(l,r:longint);
var
        o,j,m,m1,k:longint;
begin
        o:=l;
        j:=r;
        m:=a[i].a[(l+r) div 2];
        m1:=time[i].a[(l+r) div 2];
        repeat
                while (a[i].a[o]<m) or ((a[i].a[o]=m) and (time[i].a[o]<m1)) do inc(o);
                while (a[i].a[j]>m) or ((a[i].a[j]=m) and (time[i].a[j]>m1)) do dec(j);
                if o<=j then
                begin
                        k:=a[i].a[o];
                        a[i].a[o]:=a[i].a[j];
                        a[i].a[j]:=k;
                        k:=time[i].a[o];
                        time[i].a[o]:=time[i].a[j];
                        time[i].a[j]:=k;
                        inc(o);dec(j);
                end;
        until o>j;
        if l<j then qsort(l,j);
        if r>o then qsort(o,r);
end;
procedure change(var v:longint;l,r:longint;jr,gs:int64);
var
        mid:longint;
begin
        if v=0 then
        begin
                inc(tot);
                v:=tot;
        end;
        inc(size1[v],gs);
        inc(tree1[v],jr*gs);
        if l=r then exit
        else
        begin
                mid:=(l+r) div 2;
                if jr<=mid then change(left1[v],l,mid,jr,gs)
                else change(right1[v],mid+1,r,jr,gs);
        end;
end;
procedure lookfor(v,l,r,k:longint);
var
        mid:longint;
begin
        if l=r then
        begin
                ans:=ans+min(k,size1[v])*l;
                zb:=l;
        end
        else
        begin
                mid:=(l+r) div 2;
                if size1[right1[v]]>=k then lookfor(right1[v],mid+1,r,k)
                else
                begin
                        ans:=ans+tree1[right1[v]];
                        lookfor(left1[v],l,mid,k-size1[right1[v]]);
                end;
        end;
end;

procedure insert(var v:longint;l,r:longint;jr,gs:int64);
var
        i,j,k,mid:longint;
begin
        if v=0 then
        begin
                inc(tot);
                v:=tot;
        end;
        inc(size[v],gs);
        inc(tree[v],jr*gs);
        if l=r then exit
        else
        begin
                mid:=(l+r) div 2;
                if jr<=mid then insert(left[v],l,mid,jr,gs)
                else insert(right[v],mid+1,r,jr,gs);
        end;
end;

procedure find(v,l,r,k:longint);
var
        mid:longint;
begin
        if l=r then
        begin
                ans:=ans+min(k,size[v])*l;
                zb:=l;
        end
        else
        begin
                mid:=(l+r) div 2;
                if size[right[v]]>=k then find(right[v],mid+1,r,k)
                else
                begin
                        ans:=ans+tree[right[v]];
                        find(left[v],l,mid,k-size[right[v]]);
                end;
        end;
end;
begin
        assign(input,'grimoire.in');reset(input);
        assign(output,'grimoire.out');rewrite(output);
        readln(n,m);
        i:=0;
        k:=m;
        while m>0 do
        begin
                inc(i);
                dec(m);
                read(ch);
                if ch='B' then
                begin
                        for j:=1 to 6 do read(ch);
                        q[i]:=1;
                        readln(t[i],p[i]);
                        maxx:=max(p[i],maxx);
                end
                else
                begin
                        for j:=1 to 6 do read(ch);
                        q[i]:=2;
                        readln(t[i],p[i]);
                end;
        end;
        m:=k;
        for i:=1 to m do
        begin
                if q[i]=1 then
                begin
                        ans:=0;
                        find(root[t[i]],0,maxx,t[i]);
                        insert(root[t[i]],0,maxx,p[i],1);
                        if p[i]>=zb then
                        begin
                                change(root1[0],0,maxx,p[i],1);
                                change(root1[0],0,maxx,zb,-1);
                        end;
                        ans:=0;
                        lookfor(root1[0],0,maxx,n);
                        jl[i]:=ans;
                end
                else
                if q[i]=2 then
                begin
                        ans:=0;
                        find(root[t[i]],0,maxx,t[i]+1);
                        insert(root[t[i]],0,maxx,p[i],-1);
                        if p[i]>=zb then
                        begin
                                change(root1[0],0,maxx,p[i],-1);
                                change(root1[0],0,maxx,zb,1);
                        end;
                        ans:=0;
                        lookfor(root1[0],0,maxx,n);
                        jl[i]:=ans;
                end
        end;
        for i:=1 to m do writeln(jl[i]);
end.

你以为完了吗?
不,我还要给那么讲讲我的错误理解的做法打了两个小时
再看看题意:
有t种书,每次操作在某种书中添加或删除之前加入的某本书。
然后把第i种书中的前i大威力的书加入那个玛丽莎的读书清单内。
考虑删掉: 每次操作结束后回答读书清单中前n大的书的威力之和。
那么这题发现就是到sb题。
但是,我们可以用二分加线段树搞搞,好像比权值线段树好想、好写得多。
只是多想+多写了1个小时罢了
代码量惊人!

各位还是回避把,这个留给我面壁。

uses math;
type
        new=record
                a:array of int64;
        end;
        new1=record
                a:array of boolean;
        end;
var
        i,j,n,m:longint;
        l,r,k,mid,answer,ans,gs,da,sum,maxx:int64;
        q,t,p,wz,last:array[1..300000] of int64;
        kk:array[1..300000] of boolean;
        a,b,time,js,tree,size:array[1..300000] of new;
        bz:array[1..300000] of new1;
        ch:char;
procedure insert(i,x,l,r,st,value,value1:longint);
var
        m:longint;
begin
        if (l=r) then
        begin
                tree[i].a[x]:=value;
                size[i].a[x]:=value1;
        end
        else
        begin
                m:=(l+r)shr 1;
                if st<=m then insert(i,2*x,l,m,st,value,value1);
                if st>m then insert(i,2*x+1,m+1,r,st,value,value1);
                tree[i].a[x]:=tree[i].a[x*2]+tree[i].a[x*2+1];
                size[i].a[x]:=size[i].a[x*2]+size[i].a[x*2+1];
        end;
end;
procedure look_for(i,x,l,r,st,en:longint);
var
        m:longint;
begin
        if (l=st)and(r=en) then
        begin
                ans:=ans+size[i].a[x];
                answer:=answer+tree[i].a[x];
        end
        else
        begin
                m:=(l+r)shr 1;
                if en<=m then look_for(i,2*x,l,m,st,en)
                else if st>m then look_for(i,2*x+1,m+1,r,st,en)
                else
                begin
                        look_for(i,2*x,l,m,st,m);
                        look_for(i,2*x+1,m+1,r,m+1,en);
                end;
        end;
end;
procedure qsort(l,r:longint);
var
        o,j,m,m1,k:longint;
begin
        o:=l;
        j:=r;
        m:=a[i].a[(l+r) div 2];
        m1:=time[i].a[(l+r) div 2];
        repeat
                while (a[i].a[o]<m) or ((a[i].a[o]=m) and (time[i].a[o]<m1)) do inc(o);
                while (a[i].a[j]>m) or ((a[i].a[j]=m) and (time[i].a[j]>m1)) do dec(j);
                if o<=j then
                begin
                        k:=a[i].a[o];
                        a[i].a[o]:=a[i].a[j];
                        a[i].a[j]:=k;
                        k:=time[i].a[o];
                        time[i].a[o]:=time[i].a[j];
                        time[i].a[j]:=k;
                        inc(o);dec(j);
                end;
        until o>j;
        if l<j then qsort(l,j);
        if r>o then qsort(o,r);
end;
begin
        assign(input,'grimoire.in');reset(input);
        assign(output,'grimoire.out');rewrite(output);
        readln(n,m);
        i:=0;
        k:=m;
        while m>0 do
        begin
                inc(i);
                dec(m);
                read(ch);
                if ch='B' then
                begin
                        for j:=1 to 6 do read(ch);
                        q[i]:=1;
                        readln(t[i],p[i]);
                        maxx:=max(t[i],maxx);
                end
                else
                begin
                        for j:=1 to 6 do read(ch);
                        q[i]:=2;
                        readln(t[i],p[i]);
                end;
        end;
        for i:=1 to maxx do
        begin
                setlength(a[i].a,1);
                setlength(b[i].a,1);
        end;
        m:=k;
        for i:=1 to m do
        begin
                if q[i]=1 then
                begin
                        inc(a[t[i]].a[0]);
                        setlength(a[t[i]].a,a[t[i]].a[0]+1);
                        a[t[i]].a[a[t[i]].a[0]]:=p[i];
                        setlength(time[t[i]].a,a[t[i]].a[0]+1);
                        time[t[i]].a[a[t[i]].a[0]]:=i;
                end
                else
                begin
                        inc(b[t[i]].a[0]);
                        setlength(b[t[i]].a,b[t[i]].a[0]+1);
                        b[t[i]].a[b[t[i]].a[0]]:=p[i];
                        setlength(js[t[i]].a,b[t[i]].a[0]+1);
                        js[t[i]].a[b[t[i]].a[0]]:=i;
                end;
        end;
        for i:=1 to maxx do
        begin
                setlength(bz[i].a,a[i].a[0]+1);
                for j:=1 to a[i].a[0] do bz[i].a[j]:=true;
        end;
        for i:=1 to maxx do
        begin
                if a[i].a[0]>0 then
                begin
                        qsort(1,a[i].a[0]);
                end;
        end;
        for i:=1 to maxx do
        begin
                for j:=1 to a[i].a[0] do
                begin
                        wz[time[i].a[j]]:=j;
                end;
        end;
        for i:=1 to maxx do
        begin
                for j:=1 to b[i].a[0] do
                begin
                        l:=1;
                        r:=a[i].a[0];
                        while l<=r do
                        begin
                                mid:=(l+r) div 2;
                                if a[i].a[mid]>=b[i].a[j] then
                                begin
                                        r:=mid-1;
                                        answer:=mid;
                                end
                                else
                                begin
                                        l:=mid+1;
                                end;
                        end;
                        while (bz[i].a[answer]) and (answer>1) and (a[i].a[answer-1]=a[i].a[answer]) do dec(answer);
                        while (not bz[i].a[answer]) and (answer<a[i].a[0]) and (a[i].a[answer+1]=a[i].a[answer]) do inc(answer);
                        bz[i].a[answer]:=false;
                        wz[js[i].a[j]]:=answer;
                end;
        end;
        for i:=1 to maxx do
        begin
                setlength(tree[i].a,1);
                tree[i].a[0]:=a[i].a[0]*4;
                setlength(tree[i].a,tree[i].a[0]+1);
                setlength(size[i].a,1);
                size[i].a[0]:=a[i].a[0]*4;
                setlength(size[i].a,size[i].a[0]+1);
        end;
        for i:=1 to m do
        begin
                if q[i]=1 then
                begin
                        gs:=a[t[i]].a[0];
                        insert(t[i],1,1,gs,wz[i],p[i],1);
                        l:=1;
                        r:=gs;
                        while l<=r do
                        begin
                                mid:=(l+r) div 2;
                                answer:=0;
                                ans:=0;
                                look_for(t[i],1,1,gs,mid,gs);
                                if ans<t[i] then
                                begin
                                        r:=mid-1;
                                end
                                else
                                if ans>t[i] then
                                begin
                                        l:=mid+1;
                                end
                                else
                                if ans=t[i] then
                                begin
                                        break;
                                end;
                        end;
                        sum:=sum-last[t[i]]+answer;
                        writeln(sum);
                        last[t[i]]:=answer;
                end
                else
                begin
                        gs:=a[t[i]].a[0];
                        insert(t[i],1,1,gs,wz[i],0,0);
                        l:=1;
                        r:=gs;
                        while l<=r do
                        begin
                                mid:=(l+r) div 2;
                                answer:=0;
                                ans:=0;
                                look_for(t[i],1,1,gs,mid,gs);
                                if ans<t[i] then
                                begin
                                        r:=mid-1;
                                end
                                else
                                if ans>t[i] then
                                begin
                                        l:=mid+1;
                                end
                                else
                                if ans=t[i] then
                                begin
                                        break;
                                end;
                        end;
                        sum:=sum-last[t[i]]+answer;
                        writeln(sum);
                        last[t[i]]:=answer;
                end;
        end;
end.
posted @ 2018-07-12 21:46  RainbowCrown  阅读(147)  评论(0编辑  收藏  举报