[GDOI模拟2016.03.05]魔道研究
2016-03-06 13:41
323 查看
题目大意
给定t个可重集Ti,从第i个可重集中选择前i大,组成可重集S。有m个操作,分为两种,分别是给t集合删除某一个元素或是给t集合加入某一个元素。维护每次操作后S的前n大。
m,n,t≤300000,所有元素都为不大于109的正整数。
题目分析
显然我们可以使用数据结构维护T集合以及S集合。添加操作时,我们在对应Ti集合中插入该数,查询排名rank。如果rank<=i,说明它挤掉了一个数,那么我们就将Ti集合的第i+1名从S中删除,最后在S加入新数即可。
删除操作类似。
这个数据结构可以选用平衡树,配对堆等。其实权值线段树就可以解决问题,具体过程需要动态开点。
代码实现
#include <iostream> #include <cstring> #include <cstdio> #include <cctype> using namespace std; typedef long long LL; int read() { int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); } while (isdigit(ch)) { x=x*10+ch-'0'; ch=getchar(); } return x*f; } const int S=40000005; const int N=300005; const int M=300005; const int T=300005; const int P=1000000000; int n,m; struct tree { int son[S][2],size[S]; int root[T]; LL sum[S]; int tot; int newnode() { size[++tot]=0; son[tot][0]=son[tot][1]=sum[tot]=0; return tot; } void init() { memset(size,0,sizeof size); memset(sum,0,sizeof sum); memset(son,0,sizeof son); tot=0; for (int i=0;i<=300000;i++) root[i]=newnode(); } int kth(int rt,int rk,int l,int r) { if (l==r) return l; int mid=l+r>>1; if (size[son[rt][1]]>=rk) return kth(son[rt][1],rk,mid+1,r); rk-=size[son[rt][1]]; return kth(son[rt][0],rk,l,mid); } int rank(int rt,int x,int l,int r) { if (l==r) return 1; int mid=l+r>>1; if (x>mid) return rank(son[rt][1],x,mid+1,r); else return size[son[rt][1]]+rank(son[rt][0],x,l,mid); } int change(int rt,int x,int l,int r,int delta) { if (!rt) rt=newnode(); if (l==r) { sum[rt]+=delta*1ll*x; size[rt]+=delta; return rt; } int mid=l+r>>1; if (x<=mid) son[rt][0]=change(son[rt][0],x,l,mid,delta); else son[rt][1]=change(son[rt][1],x,mid+1,r,delta); int ls=son[rt][0],rs=son[rt][1]; sum[rt]=sum[ls]+sum[rs]; size[rt]=size[ls]+size[rs]; return rt; } LL query(int rt,int kth,int l,int r) { if (l==r) return l*1ll*min(kth,size[rt]); int mid=l+r>>1; if (kth<=size[son[rt][1]]) return query(son[rt][1],kth,mid+1,r); else return sum[son[rt][1]]+query(son[rt][0],kth-size[son[rt][1]],l,mid); } }t; int main() { freopen("grimoire.in","r",stdin); freopen("grimoire.out","w",stdout); n=read(),m=read(); t.init(); for (int i=1;i<=m;i++) { char cmd=getchar(); while (!isalpha(cmd)) cmd=getchar(); int ti=read(),pi=read(); if (cmd=='B') { t.change(t.root[ti],pi,1,P,1); int rk=t.rank(t.root[ti],pi,1,P); if (rk<=ti) { if (t.size[t.root[ti]]>ti) { int num=t.kth(t.root[ti],ti+1,1,P); t.change(t.root[0],num,1,P,-1); } t.change(t.root[0],pi,1,P,1); } LL ans=t.query(t.root[0],n,1,P); printf("%lld\n",ans); } else { int rk=t.rank(t.root[ti],pi,1,P); t.change(t.root[ti],pi,1,P,-1); if (rk<=ti) { if (t.size[t.root[ti]]>=ti) { int num=t.kth(t.root[ti],ti,1,P); t.change(t.root[0],num,1,P,1); } t.change(t.root[0],pi,1,P,-1); } LL ans=t.query(t.root[0],n,1,P); printf("%lld\n",ans); } } fclose(stdin); fclose(stdout); return 0; }
相关文章推荐
- 哈希链表:提高链表访问效率
- Java关键字this、super使用总结
- C#取硬盘、CPU、主板、网卡的序号 ManagementObjectSearcher (WMI)
- JavaScript学习笔记(7)——JavaScript语法之函数
- 002.unity刚体
- Cocoa Class是啥
- 【慕课笔记】1-1 文件的编码
- bzoj 3524/2223(主席树)
- 谢泽文的C++第一次实验报告1
- 课后实验1--四则运算
- tkinter笔记六
- NLPIR2016相关功能的java实现
- deeplearning-tricks
- 【实战】初识ListView及提高效率
- 域控制器主机时间同步
- sublime模式下开启vim并修改esc
- Mac中Eclipse代码自动整理快捷键
- 第三章SQL编程
- VS编译错误:syntax error : missing ';' before 'type'
- Linux内核分析——操作系统是如何工作的