jzoj4270 [NOIP2015模拟10.27]魔道研究 线段树

Description


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

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

Solution


开n+1棵线段树,其中n棵维护排名,第n+1棵求前n大,然后就做完了
天啊我好菜居然没1A

Code


#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

typedef long long LL;
const int LIM=1000000000;
const int N=300005;

struct treeNode {int l,r,size; LL sum;} t[N*75];

int root[N],tot;

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void modify(int &now,int tl,int tr,int x,int v) {
    if (!now) now=++tot;
    t[now].size+=v; t[now].sum+=(v>0)?(x):(-x);
    if (tl==tr) return ;
    int mid=(tl+tr)/2;
    if (x<=mid) modify(t[now].l,tl,mid,x,v);
    else modify(t[now].r,mid+1,tr,x,v);
}

LL query(int now,int tl,int tr,int k) {
    if (t[now].size<=k) return t[now].sum;
    if (tl==tr) return k*tl;
    int mid=(tl+tr)/2;
    if (t[t[now].r].size>=k) return query(t[now].r,mid+1,tr,k);
    else return t[t[now].r].sum+query(t[now].l,tl,mid,k-t[t[now].r].size);
}

int kth(int now,int tl,int tr,int k) {
    if (t[now].size<k) return 0;
    if (tl==tr) return tl;
    int mid=(tl+tr)>>1;
    if (t[t[now].r].size>=k) return kth(t[now].r,mid+1,tr,k);
    else return kth(t[now].l,tl,mid,k-t[t[now].r].size);
}

int rank(int now,int tl,int tr,int x) {
    if (tl==tr) return t[now].size;
    int mid=(tl+tr)>>1;
    if (x>=mid) return rank(t[now].r,mid+1,tr,x);
    else return rank(t[now].l,tl,mid,x)+t[t[now].r].size;
}

int main(void) {
    freopen("grimoire3.in","r",stdin);
    freopen("grimoire.out","w",stdout); int cnt=0;
    for (int n=read(),m=read();m--;) {
        char opt[10]; scanf("%s",opt);
        int x=read(),y=read();
        if (++cnt==1037) {
            int gg=0;
            gg++;
        }
        if (opt[0]=='B') {
            if (rank(root[x],1,LIM,y+1)+1<=x) {
                int tmp=kth(root[x],1,LIM,x);
                if (tmp) modify(root[N-1],1,LIM,tmp,-1);
                modify(root[N-1],1,LIM,y,1);
            }
            modify(root[x],1,LIM,y,1);
        } else {
            if (rank(root[x],1,LIM,y+1)+1<=x) {
                modify(root[N-1],1,LIM,y,-1);
                int tmp=kth(root[x],1,LIM,x+1);
                if (tmp) modify(root[N-1],1,LIM,tmp,1);
            }
            modify(root[x],1,LIM,y,-1);
        }
        printf("%lld\n", query(root[N-1],1,LIM,n));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/81018788