魔道研究

题面

思路

简单的想,就是在 \(T\) 个可重集合每个中选出 \(k\) 个最大的数组成新的可重集合,其中 \(k\) 为其编号

然后在新的集合中选前 \(n\) 大的数,求其和

考虑开 \(T + 1\) 个权值线段树,维护对应的 \(T\) 个可重集合和答案可能在的第 \(T + 1\) 个代表新的集合的线段树

由于空间限制,我们需要动态开点(其实动态开点很简单,线段树二分下去时,遇到一个空节点再使用它。如此一来,在只需开可能使用的节点数)

然后维护区间个数,区间和(注意一个点可能有多个数)

因为是动态开点,所以再记录它的左、右子树的编号

对于 \(B\) 操作,我们直接在根为 \(t\) 的线段树中加入,然后考虑它能不能进入第 \(T + 1\) 棵线段树成为可能的答案。

即查它在第 \(t\) 棵线段树中的从大到小的排名(其实就是求第 \(t\) 棵线段树中 \(p\) 到上限的个数)和)。

如果它的排名 \(\leq t\) ,则可能加入第 \(T + 1\) 个线段树。加入后把现在排名为 \(t+1\) 的数从第 \(T + 1\) 棵线段树中删去(即原先的排名为 \(t\) 的数,它在第 \(T + 1\) 棵线段树中),当然,如果有的话。

对于 \(R\) 操作,就是 \(B\) 操作的逆操作,具体见代码。

\(Code\)

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL; const int N = 3e5 , Len = 1e9;
int n , m , tot , len = N + 1;
LL tr[18000005][5]; inline void New(int t , int x){if (!tr[t][x]) tr[t][x] = ++len;} inline void update(int t , int l , int r , int p , int v)
{
tr[t][2] += (LL)v;
tr[t][3] += (LL)p * v;
if (l == r) return;
int mid = (l + r) >> 1;
if (p <= mid)
{
if (!tr[t][0]) New(t , 0);
update(tr[t][0] , l , mid , p , v);
}
else{
if (!tr[t][1]) New(t , 1);
update(tr[t][1] , mid + 1 , r , p , v);
}
} inline int findk(int t , int l , int r , int x , int y)
{
if (l >= x && r <= y) return (int)tr[t][2];
int res = 0 , mid = (l + r) >> 1;
if (x <= mid && tr[tr[t][0]][2]) res += findk(tr[t][0] , l , mid , x , y);
if (y > mid && tr[tr[t][1]][2]) res += findk(tr[t][1] , mid + 1 , r , x , y);
return res;
} inline int kfind(int t , int l , int r , int k)
{
if (l == r) return k <= tr[t][2] ? l : 0;
int mid = (l + r) >> 1;
if (tr[tr[t][1]][2] < k) return kfind(tr[t][0] , l , mid , k - tr[tr[t][1]][2]);
else return kfind(tr[t][1] , mid + 1 , r , k);
} inline LL query(int t , int l , int r , int k)
{
if (l == r) return 1LL * min(1LL * k , tr[t][2]) * l;
int mid = (l + r) >> 1;
LL res = 0;
if (tr[tr[t][1]][2] <= k)
{
res += tr[tr[t][1]][3];
if (tr[tr[t][0]][2] && k > tr[tr[t][1]][2])
res += query(tr[t][0] , l , mid , k - tr[tr[t][1]][2]);
}
else{
if (tr[tr[t][1]][2]) res += query(tr[t][1] , mid + 1 , r , k);
}
return res;
} int main()
{
freopen("grimoire.in" , "r" , stdin);
freopen("grimoire.out" , "w" , stdout);
scanf("%d%d" , &n , &m);
int t , p;
char op[8];
for(register int i = 1; i <= m; i++)
{
int s1 , s2;
scanf("%s%d%d" , op , &t , &p);
if (op[0] == 'B')
{
update(t , 1 , Len , p , 1);
s1 = findk(t , 1 , Len , p , Len);
if (s1 <= t)
{
update(N + 1 , 1 , Len , p , 1);
s2 = kfind(t , 1 , Len , t + 1);
if (s2) update(N + 1 , 1 , Len , s2 , -1);
}
}
else{
s1 = findk(t , 1 , Len , p , Len);
update(t , 1 , Len , p , -1);
if (s1 <= t)
{
update(N + 1 , 1 , Len , p , -1);
s2 = kfind(t , 1 , Len , t);
if (s2) update(N + 1 , 1 , Len , s2 , 1);
}
}
printf("%lld\n" , query(N + 1 , 1 , Len , n));
}
}

最新文章

  1. python中的默认参数
  2. 一张图系列——为什么在DllMain里面创建了线程并Wait会卡死
  3. C# Word生成PDF
  4. mongo管理工具
  5. C#MD5为密码加密
  6. instanceof 变量是否属于某一类 class 的实例
  7. HttpAsyncClient 做并发长连接的一个实例
  8. Yii框架上传后展示图片
  9. js中盒子模型常用的属性你还记得几个?
  10. 最大流算法之Dinic
  11. arm处理器
  12. 基于java生成二维码
  13. iframe子页面与父页面元素的访问以及js变量的访问
  14. bug定位
  15. m个苹果放入n个篮子
  16. 洛谷P4027 [NOI2007]货币兑换(dp 斜率优化 cdq 二分)
  17. ajaxupload 异步上传工具
  18. java——关于异常处理机制的简单原理和应用
  19. [Cpp primer] Library vector Type
  20. python 替换指定目录下,所有文本字符串

热门文章

  1. 2. 第一个PyQt5 程序 Helloword!
  2. 30位以内随机产生时间戳加随机数id
  3. 2.6:Python数据存取-文件、文件夹及目录、数据库
  4. 【面试题总结】Java并发-多线程、JUC详述(思维导图)
  5. dotnet new cli 以及Abp-cli命令的简单使用
  6. Java单例模式的最佳实践?
  7. psutil模块使用(系统监控,性能分析,进程管理)
  8. 数据库MySQL(完结)
  9. selenium 输入文本时报InvalidElementStateException: Message: invalid element state
  10. C/S UDP通信实践踩坑记录与对于ICMP的进一步认识