题目大意
给定一些书和你所能携带的书的总量,问在每次操作后你能获得的最大价值
解题思路
权值线段树查找区间第
大进行踢出操作,然后借书相当于区间增值,由于空间很大,所以需要动态开点,要不然会
注意:数据很大,最好不要用宏定义最小值,要不然会迷之WA
代码
#include<cstdio>
#include<algorithm>
#define N 17000021
#define LL long long
using namespace std;int cnt;
int root[N],le[N],ri[N],t[N],n,m,x,y;
LL s[N],ans,f;char c;
inline LL read()
{
f=0;
while(c=getchar(),c<=47||c>=58);f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
return f;
}
void write(LL x){if(x>9) write(x/10);putchar(x%10+48);return;}
void add(int &k,int l,int r,int x,int d)//&是为了动态开店节省空间
{
if(!k) k=++cnt;//动态开点
if(d) t[k]++,s[k]+=x;else t[k]--,s[k]-=x;//修改
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) add(le[k],l,mid,x,d);else add(ri[k],mid+1,r,x,d);
return;
}
int ask(int k,int l,int r,int x)//查询操作
{
if(l==r)
{
ans+=l*min(x,t[k]);
return l;
}
int mid=(l+r)>>1;
if(t[ri[k]]>=x) return ask(ri[k],mid+1,r,x);//在右边
else
{
ans+=s[ri[k]];
return ask(le[k],l,mid,x-t[ri[k]]);//在左边
}
}
int main()
{
freopen("grimoire.in","r",stdin);
freopen("grimoire.out","w",stdout);
n=read();m=read();
for (int i=1;i<=m;i++)
{
scanf("\n%c",&c);
if(c=='B')
{
x=read();y=read();
int k=ask(root[x],0,1e9,x);
add(root[x],0,1e9,y,1);//借书
if(y>=k)//超过了
{
add(root[0],0,1e9,y,1);//y来
add(root[0],0,1e9,k,0);//k走
}
}
else
{
x=read();y=read();
int k=ask(root[x],0,1e9,x+1);
add(root[x],0,1e9,y,0);//还书
if(y>=k)//超过了
{
add(root[0],0,1e9,y,0);//y走
add(root[0],0,1e9,k,1);//k来
}
}
ans=0;
ask(root[0],0,1e9,n);//查询
write(ans);putchar(10);//输出
}
}