您的位置:首页 > 其它

[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: