2020.7.25T2魔道研究(jz暑假训练day10)

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

赛时

一直考虑正解,线段树主席数splay都想了想,但是由于自己实在是太*,所以没想到分别维护小与大的数据结构,然后就0分。

正解

要求操作有插入,删除,以及求第k大(求前n大的答案),那么啥都可以搞了,最后打了权值线段树,然后动态开点就行了

#include<cstdio>
#include<iostream>
#define N 300007
using namespace std;
const long long maxn=1000000010;//最大的权值,可以考虑先离散化
int n,m,cnt,son[N*100][2],num[N*100],root[N];
long long ans,val[N*100];
int query(int rt,int l,int r,int k){
	if(l==r){
		ans+=min(k,num[rt])*l;
		return l;
	}
	int mid=l+r>>1;
	if(k<=num[son[rt][1]]) query(son[rt][1],mid+1,r,k);
	else{
		ans+=val[son[rt][1]];
		query(son[rt][0],l,mid,k-num[son[rt][1]]);
	}
}
void change(int &rt,int l,int r,int k,int bz){
	if(!rt) rt=++cnt;
	num[rt]+=bz;val[rt]+=bz*k;
	if(l==r) return;
	int mid=l+r>>1;
	if(k<=mid) change(son[rt][0],l,mid,k,bz);
	else change(son[rt][1],mid+1,r,k,bz);
}
int main(){
	freopen("grimoire.in","r",stdin);
	freopen("grimoire.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int x,y;
		char s[10];
		scanf("%s%d%d",s+1,&x,&y);
		if(s[1]=='B'){
			int t=query(root[x],0,maxn,x);
			change(root[x],0,maxn,y,1);
			if(t<y){
				change(root[0],0,maxn,y,1);
				change(root[0],0,maxn,t,-1);
			}
		}else{
			int t=query(root[x],0,maxn,x+1);
			change(root[x],0,maxn,y,-1);
			if(y>t){
				change(root[0],0,maxn,y,-1);
				change(root[0],0,maxn,t,1);
			}
		}
		ans=0;
		query(root[0],0,maxn,n);
		printf("%lld\n",ans);
	}
}

猜你喜欢

转载自blog.csdn.net/jay_zai/article/details/107618227