• 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.
    
    我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。
  • 相关阅读:
    面向对象三大特性之多态
    作业
    面向对象三大特性之封装
    面向对象三大特性之继承
    面向对象(一)
    subprocess, re模块,logging, 包等使用方法
    模块二之序列化模块以及collections模块
    常用模块
    内置函数补充,函数递归,模块
    生成器以及面向过程编程
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148410.html
Copyright © 2020-2023  润新知