Description
“我希望能使用更多的魔法。不对,是预定能使用啦。最终我要被大家称呼为大魔法使。为此我决定不惜一切努力。”
——《The Grimoire of Marisa》雾雨魔理沙
魔理沙一如既往地去帕秋莉的大图书馆去借魔导书(Grimoire) 来学习魔道。
最开始的时候,魔理沙只是一本一本地进行研究。然而在符卡战中,魔理沙还是战不过帕秋莉。
好在魔理沙对自己的借还和研究结果进行了记录,从而发现了那些魔导书的精妙之处。
帕秋莉的那些魔导书,每本都有一个类别编号ti 和威力大小pi。而想要获得最有威力的魔法,就必须同时研究一些魔导书。而研究的这些魔导书就必须要满足,类别编号为T 的书的本数小于等于T,并且总共的本数小于等于一个给定的数N。而研究这些魔导书之后习得的魔法的威力就是被研究的魔导书的威力之和。
为了击败帕秋莉,魔理沙想要利用自己发现的规律来获得最有威力的魔法。
她列出了计划中之后M 次的借还事件,并想要知道每个事件之后自己所能获得的魔法的最大威力。可她忙于魔法材料——蘑菇的收集,于是这个问题就交给你来解决了。
Solution
这道题,一眼就是数据结构维护。
那需要查找第k大值,求和,删除,加入,那么明显的就有数据结构可以维护了:1、线段树(或主席树);2、splay;3、treap;4、替罪羊树(表示并不会)
我打了一颗线段树,打法十分显然。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define ll long long
const int maxn=300007;
const int da=1000000007;
using namespace std;
int i,j,k,l,tt,n,m,p,num;
ll ans,ans1,ans2;
int root[maxn];
struct node{
int tot,l,r;
ll sum;
}t[maxn*92];
char s[10];
void insert(int &v,int l,int r,int z){
if(!v)v=++num;
t[v].sum+=z;
t[v].tot+=1;
if(l==r)return;
int mid=(l+r)/2;
if(z<=mid) insert(t[v].l,l,mid,z);
else insert(t[v].r,mid+1,r,z);
}
void delet(int v,int l,int r,int z){
if(!v)v=++num;
t[v].sum-=z;
t[v].tot-=1;
if(l==r)return;
int mid=(l+r)/2;
if(z<=mid) delet(t[v].l,l,mid,z);
else delet(t[v].r,mid+1,r,z);
}
void dikda(int x,int l,int r,int z){
if(l==r){
ans1=l;
return;
}
int mid=(l+r)/2;
if(t[t[x].r].tot>=z)dikda(t[x].r,mid+1,r,z);
else dikda(t[x].l,l,mid,z-t[t[x].r].tot);
}
void get(int x,int l,int r,int z){
if(l==r){
ans=ans+min(t[x].tot,z)*l;
return;
}
int mid=(l+r)/2;
if(t[t[x].r].tot>=z)get(t[x].r,mid+1,r,z);
else get(t[x].l,l,mid,z-t[t[x].r].tot),ans+=t[t[x].r].sum;
}
int main(){
//freopen("grimoire.in","r",stdin);
//freopen("grimoire.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,m){
scanf("%s%d%d",s,&tt,&p);
if(s[0]=='B'){
if(t[root[tt]].tot>=tt){
dikda(root[tt],1,da,tt);
}
else ans1=0;
if(p>=ans1){
insert(root[0],1,da,p);
if(ans1>0)delet(root[0],1,da,ans1);
}
insert(root[tt],1,da,p);
}
else{
if(t[root[tt]].tot>tt){
dikda(root[tt],1,da,tt+1);
}
else ans1=0;
if(p>=ans1){
delet(root[0],1,da,p);
if(ans1>0)insert(root[0],1,da,ans1);
}
delet(root[tt],1,da,p);
}
ans=0;
get(root[0],1,da,n);
printf("%lld\n",ans);
}
}